mirror of
https://github.com/crater-invoice/crater.git
synced 2025-10-27 11:41:09 -04:00
Compare commits
108 Commits
6.0.3
...
mail-sende
| Author | SHA1 | Date | |
|---|---|---|---|
| dea73bcdf8 | |||
| aececb8575 | |||
| 2bea727d19 | |||
| aede1f76d0 | |||
| 959aa257b4 | |||
| b4aa254b68 | |||
| c1f2af5174 | |||
| 05d5ce26fd | |||
| 393fe20010 | |||
| 57bdbd2897 | |||
| 7447cc24f9 | |||
| 889d22d92c | |||
| bc8f2cd484 | |||
| 4e47f58bad | |||
| d8c429912e | |||
| 0aaf0e7e75 | |||
| 3d0b89bb4d | |||
| 38c4b9ebce | |||
| 7be59e78e0 | |||
| 204483836a | |||
| 33bc9ded65 | |||
| 4271ef451e | |||
| 6eb44fba93 | |||
| 96e7300583 | |||
| a479d966d1 | |||
| bca2794c4c | |||
| cb88c19059 | |||
| 946c7efab4 | |||
| d7b1d15f93 | |||
| 94e1efe115 | |||
| b0e38b74e9 | |||
| 157559cc05 | |||
| 9d1484d62d | |||
| 654dd9e64d | |||
| 7cde971f8b | |||
| 4e7441a5cf | |||
| b714833b06 | |||
| 88035ea490 | |||
| 80847529fa | |||
| 18507ddb6f | |||
| 7275f3dd47 | |||
| e31f947aba | |||
| 7ba120db31 | |||
| bc73ed8c9e | |||
| b1689dd2c6 | |||
| f6c59b7423 | |||
| 2cadcad485 | |||
| 04deade111 | |||
| ee0632f0d3 | |||
| f6771dafd3 | |||
| fadef0ea07 | |||
| c07e44520a | |||
| 6552c4edd6 | |||
| 5183a825e6 | |||
| 83a7c97e9e | |||
| eea3925fcd | |||
| 9a0de9f64f | |||
| a23644c9d8 | |||
| b884001e87 | |||
| bb54edc147 | |||
| 25c43ab4d2 | |||
| 388d00241b | |||
| 69d8c95557 | |||
| ea9748ca68 | |||
| 66a5501bd2 | |||
| c897521137 | |||
| adf4b3a74d | |||
| cc737593b7 | |||
| 9356c309a2 | |||
| 35da80103e | |||
| 99f553f1c3 | |||
| 3f4305c7cb | |||
| a678b4d272 | |||
| 0c83456866 | |||
| 2cb51b84c7 | |||
| 3908878109 | |||
| 6970a4f243 | |||
| 5720803116 | |||
| 351e6617d9 | |||
| ffa7906382 | |||
| 2a43ec9e9d | |||
| 48f9da14ba | |||
| 4153d10a0a | |||
| 1322ed15dc | |||
| a452ec5eaf | |||
| b819307612 | |||
| 7202fdcbf2 | |||
| c28fc073e4 | |||
| 439fc4e002 | |||
| ca15751a5f | |||
| 50637f5f7c | |||
| e3219baad2 | |||
| 8de8a07e3e | |||
| ab28ba38ce | |||
| 7a27317f1a | |||
| ab153963e4 | |||
| 65dd1eca01 | |||
| bed05fc21f | |||
| 0578122fc3 | |||
| ce3db7d0c6 | |||
| 854ae10198 | |||
| 2383e89daa | |||
| 6529fa1892 | |||
| eef74fd2fc | |||
| 2f69b6fa71 | |||
| 7170fb0cef | |||
| db7a084a19 | |||
| e24a89fe39 |
161
.github/workflows/uffizzi-build.yml
vendored
Normal file
161
.github/workflows/uffizzi-build.yml
vendored
Normal file
@ -0,0 +1,161 @@
|
||||
name: Build PR Image
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened,synchronize,reopened,closed]
|
||||
|
||||
jobs:
|
||||
|
||||
build-application:
|
||||
name: Build and Push `application`
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.action != 'closed' }}
|
||||
outputs:
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
steps:
|
||||
- name: Checkout git repo
|
||||
uses: actions/checkout@v3
|
||||
- name: Generate UUID image name
|
||||
id: uuid
|
||||
run: echo "UUID_TAG_APP=$(uuidgen)" >> $GITHUB_ENV
|
||||
- name: Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
with:
|
||||
images: registry.uffizzi.com/${{ env.UUID_TAG_APP }}
|
||||
tags: type=raw,value=60d
|
||||
- name: Build and Push Image to registry.uffizzi.com ephemeral registry
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
push: true
|
||||
context: ./
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
file: ./uffizzi/Dockerfile
|
||||
|
||||
build-nginx:
|
||||
needs:
|
||||
- build-application
|
||||
name: Build and Push `nginx`
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.action != 'closed' }}
|
||||
outputs:
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
steps:
|
||||
- name: Checkout git repo
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Generate UUID image name
|
||||
id: uuid
|
||||
run: echo "UUID_TAG_NGINX=$(uuidgen)" >> $GITHUB_ENV
|
||||
- name: Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
with:
|
||||
images: registry.uffizzi.com/${{ env.UUID_TAG_NGINX }}
|
||||
tags: type=raw,value=60d
|
||||
- name: Build and Push Image to Uffizzi ephemeral registry
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
push: true
|
||||
context: ./
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
file: ./uffizzi/nginx/Dockerfile
|
||||
build-args: |
|
||||
BASE_IMAGE=${{ needs.build-application.outputs.tags }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
|
||||
build-crond:
|
||||
name: Build and Push `crond`
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.action != 'closed' }}
|
||||
outputs:
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
steps:
|
||||
- name: Checkout git repo
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Generate UUID image name
|
||||
id: uuid
|
||||
run: echo "UUID_TAG_CROND=$(uuidgen)" >> $GITHUB_ENV
|
||||
- name: Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
with:
|
||||
images: registry.uffizzi.com/${{ env.UUID_TAG_CROND }}
|
||||
tags: type=raw,value=60d
|
||||
- name: Build and Push Image to registry.uffizzi.com ephemeral registry
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
push: true
|
||||
context: ./
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
file: ./uffizzi/crond/Dockerfile
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
|
||||
|
||||
render-compose-file:
|
||||
name: Render Docker Compose File
|
||||
# Pass output of this workflow to another triggered by `workflow_run` event.
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
compose-file-cache-key: ${{ steps.hash.outputs.hash }}
|
||||
needs:
|
||||
- build-application
|
||||
- build-nginx
|
||||
- build-crond
|
||||
steps:
|
||||
- name: Checkout git repo
|
||||
uses: actions/checkout@v3
|
||||
- name: Render Compose File
|
||||
run: |
|
||||
APP_IMAGE=$(echo ${{ needs.build-application.outputs.tags }})
|
||||
export APP_IMAGE
|
||||
NGINX_IMAGE=$(echo ${{ needs.build-nginx.outputs.tags }})
|
||||
export NGINX_IMAGE
|
||||
CROND_IMAGE=$(echo ${{ needs.build-crond.outputs.tags }})
|
||||
export CROND_IMAGE
|
||||
# Render simple template from environment variables.
|
||||
envsubst < ./uffizzi/docker-compose.uffizzi.yml > docker-compose.rendered.yml
|
||||
cat docker-compose.rendered.yml
|
||||
- name: Upload Rendered Compose File as Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: preview-spec
|
||||
path: docker-compose.rendered.yml
|
||||
retention-days: 2
|
||||
- name: Serialize PR Event to File
|
||||
run: |
|
||||
cat << EOF > event.json
|
||||
${{ toJSON(github.event) }}
|
||||
|
||||
EOF
|
||||
- name: Upload PR Event as Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: preview-spec
|
||||
path: event.json
|
||||
retention-days: 2
|
||||
|
||||
delete-preview:
|
||||
name: Call for Preview Deletion
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.action == 'closed' }}
|
||||
steps:
|
||||
# If this PR is closing, we will not render a compose file nor pass it to the next workflow.
|
||||
- name: Serialize PR Event to File
|
||||
run: echo '${{ toJSON(github.event) }}' > event.json
|
||||
- name: Upload PR Event as Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: preview-spec
|
||||
path: event.json
|
||||
retention-days: 2
|
||||
|
||||
84
.github/workflows/uffizzi-preview.yml
vendored
Normal file
84
.github/workflows/uffizzi-preview.yml
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
name: Deploy Uffizzi Preview
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows:
|
||||
- "Build PR Image"
|
||||
types:
|
||||
- completed
|
||||
|
||||
|
||||
jobs:
|
||||
cache-compose-file:
|
||||
name: Cache Compose File
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
compose-file-cache-key: ${{ env.COMPOSE_FILE_HASH }}
|
||||
pr-number: ${{ env.PR_NUMBER }}
|
||||
steps:
|
||||
- name: 'Download artifacts'
|
||||
# Fetch output (zip archive) from the workflow run that triggered this workflow.
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
run_id: context.payload.workflow_run.id,
|
||||
});
|
||||
let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => {
|
||||
return artifact.name == "preview-spec"
|
||||
})[0];
|
||||
let download = await github.rest.actions.downloadArtifact({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
artifact_id: matchArtifact.id,
|
||||
archive_format: 'zip',
|
||||
});
|
||||
let fs = require('fs');
|
||||
fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/preview-spec.zip`, Buffer.from(download.data));
|
||||
- name: 'Unzip artifact'
|
||||
run: unzip preview-spec.zip
|
||||
- name: Read Event into ENV
|
||||
run: |
|
||||
echo 'EVENT_JSON<<EOF' >> $GITHUB_ENV
|
||||
cat event.json >> $GITHUB_ENV
|
||||
echo 'EOF' >> $GITHUB_ENV
|
||||
- name: Hash Rendered Compose File
|
||||
id: hash
|
||||
# If the previous workflow was triggered by a PR close event, we will not have a compose file artifact.
|
||||
if: ${{ fromJSON(env.EVENT_JSON).action != 'closed' }}
|
||||
run: echo "COMPOSE_FILE_HASH=$(md5sum docker-compose.rendered.yml | awk '{ print $1 }')" >> $GITHUB_ENV
|
||||
- name: Cache Rendered Compose File
|
||||
if: ${{ fromJSON(env.EVENT_JSON).action != 'closed' }}
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: docker-compose.rendered.yml
|
||||
key: ${{ env.COMPOSE_FILE_HASH }}
|
||||
|
||||
- name: Read PR Number From Event Object
|
||||
id: pr
|
||||
run: echo "PR_NUMBER=${{ fromJSON(env.EVENT_JSON).number }}" >> $GITHUB_ENV
|
||||
|
||||
- name: DEBUG - Print Job Outputs
|
||||
if: ${{ runner.debug }}
|
||||
run: |
|
||||
echo "PR number: ${{ env.PR_NUMBER }}"
|
||||
echo "Compose file hash: ${{ env.COMPOSE_FILE_HASH }}"
|
||||
cat event.json
|
||||
deploy-uffizzi-preview:
|
||||
name: Use Remote Workflow to Preview on Uffizzi
|
||||
needs:
|
||||
- cache-compose-file
|
||||
uses: UffizziCloud/preview-action/.github/workflows/reusable.yaml@v2.6.1
|
||||
with:
|
||||
# If this workflow was triggered by a PR close event, cache-key will be an empty string
|
||||
# and this reusable workflow will delete the preview deployment.
|
||||
compose-file-cache-key: ${{ needs.cache-compose-file.outputs.compose-file-cache-key }}
|
||||
compose-file-cache-path: docker-compose.rendered.yml
|
||||
server: https://app.uffizzi.com/
|
||||
pr-number: ${{ needs.cache-compose-file.outputs.pr-number }}
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
id-token: write
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -16,3 +16,5 @@ Homestead.yaml
|
||||
.gitkeep
|
||||
/public/docs
|
||||
/.scribe
|
||||
!storage/fonts/.gitkeep
|
||||
.DS_Store
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
FROM php:7.4-fpm
|
||||
FROM php:8.1-fpm
|
||||
|
||||
# Arguments defined in docker-compose.yml
|
||||
ARG user
|
||||
|
||||
@ -40,10 +40,13 @@ class CheckInvoiceStatus extends Command
|
||||
public function handle()
|
||||
{
|
||||
$date = Carbon::now();
|
||||
$invoices = Invoice::where('status', '<>', Invoice::STATUS_COMPLETED)->whereDate('due_date', '<', $date)->get();
|
||||
$invoices = Invoice::whereNotIn('status', [Invoice::STATUS_COMPLETED, Invoice::STATUS_DRAFT])
|
||||
->where('overdue', false)
|
||||
->whereDate('due_date', '<', $date)
|
||||
->get();
|
||||
|
||||
foreach ($invoices as $invoice) {
|
||||
$invoice->status = Invoice::STATUS_OVERDUE;
|
||||
$invoice->overdue = true;
|
||||
printf("Invoice %s is OVERDUE \n", $invoice->invoice_number);
|
||||
$invoice->save();
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@ class CreateTemplateCommand extends Command
|
||||
copy(public_path("/build/img/PDF/{$type}1.png"), public_path("/build/img/PDF/{$templateName}.png"));
|
||||
copy(resource_path("/static/img/PDF/{$type}1.png"), resource_path("/static/img/PDF/{$templateName}.png"));
|
||||
|
||||
$path = resource_path("app/pdf/{$type}/{$templateName}.blade.php");
|
||||
$path = resource_path("views/app/pdf/{$type}/{$templateName}.blade.php");
|
||||
$type = ucfirst($type);
|
||||
$this->info("{$type} Template created successfully at ".$path);
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Crater\Console;
|
||||
|
||||
use Crater\Models\CompanySetting;
|
||||
use Crater\Models\RecurringInvoice;
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
@ -37,9 +38,11 @@ class Kernel extends ConsoleKernel
|
||||
|
||||
$recurringInvoices = RecurringInvoice::where('status', 'ACTIVE')->get();
|
||||
foreach ($recurringInvoices as $recurringInvoice) {
|
||||
$timeZone = CompanySetting::getSetting('time_zone', $recurringInvoice->company_id);
|
||||
|
||||
$schedule->call(function () use ($recurringInvoice) {
|
||||
$recurringInvoice->generateInvoice();
|
||||
})->cron($recurringInvoice->frequency);
|
||||
})->cron($recurringInvoice->frequency)->timezone($timeZone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,7 +55,9 @@ class BootstrapController extends Controller
|
||||
'admin_portal_logo',
|
||||
'login_page_logo',
|
||||
'login_page_heading',
|
||||
'login_page_description'
|
||||
'login_page_description',
|
||||
'admin_page_title',
|
||||
'copyright_text'
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Crater\Http\Controllers\V1\Admin\MailSender;
|
||||
|
||||
use Crater\Http\Controllers\Controller;
|
||||
use Crater\Http\Resources\MailSenderResource;
|
||||
use Crater\Models\MailSender;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class GetAllMailSendersController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function __invoke(Request $request)
|
||||
{
|
||||
$mailSenders = MailSender::whereCompany()->get();
|
||||
|
||||
return MailSenderResource::collection($mailSenders);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace Crater\Http\Controllers\V1\Admin\MailSender;
|
||||
|
||||
use Crater\Http\Controllers\Controller;
|
||||
use Crater\Http\Requests\MailSenderRequest;
|
||||
use Crater\Http\Resources\MailSenderResource;
|
||||
use Crater\Models\MailSender;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class MailSenderController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('viewAny', MailSender::class);
|
||||
|
||||
$limit = $request->has('limit') ? $request->limit : 10;
|
||||
|
||||
$mailSenders = MailSender::whereCompany()
|
||||
->applyFilters($request->all())
|
||||
->paginateData($limit);
|
||||
|
||||
return (MailSenderResource::collection($mailSenders))
|
||||
->additional(['meta' => [
|
||||
'mail_sender_total_count' => MailSender::whereCompany()->count(),
|
||||
]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(MailSenderRequest $request)
|
||||
{
|
||||
$this->authorize('create', MailSender::class);
|
||||
|
||||
$mailSender = MailSender::createFromRequest($request);
|
||||
|
||||
return new MailSenderResource($mailSender);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param \Crater\Models\SenderMail $senderMail
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(MailSender $mailSender)
|
||||
{
|
||||
$this->authorize('view', $mailSender);
|
||||
|
||||
return new MailSenderResource($mailSender);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Crater\Models\SenderMail $senderMail
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(MailSenderRequest $request, MailSender $mailSender)
|
||||
{
|
||||
$this->authorize('update', $mailSender);
|
||||
|
||||
$mailSender->updateFromRequest($request);
|
||||
|
||||
return new MailSenderResource($mailSender);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \Crater\Models\SenderMail $senderMail
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(MailSender $mailSender)
|
||||
{
|
||||
$this->authorize('delete', $mailSender);
|
||||
|
||||
if ($mailSender->is_default) {
|
||||
return respondJson('You can\'t remove default mail sender.', 'You can\'t remove default mail sender.');
|
||||
}
|
||||
|
||||
$mailSender->delete();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -3,18 +3,18 @@
|
||||
namespace Crater\Http\Controllers\V1\Admin\Modules;
|
||||
|
||||
use Crater\Http\Controllers\Controller;
|
||||
use Crater\Http\Requests\UnzipUpdateRequest;
|
||||
use Crater\Space\ModuleInstaller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class UnzipModuleController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Crater\Http\Requests\UnzipUpdateRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function __invoke(Request $request)
|
||||
public function __invoke(UnzipUpdateRequest $request)
|
||||
{
|
||||
$this->authorize('manage modules');
|
||||
|
||||
|
||||
@ -3,18 +3,18 @@
|
||||
namespace Crater\Http\Controllers\V1\Admin\Modules;
|
||||
|
||||
use Crater\Http\Controllers\Controller;
|
||||
use Crater\Http\Requests\UploadModuleRequest;
|
||||
use Crater\Space\ModuleInstaller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class UploadModuleController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Crater\Http\Requests\UploadModuleRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function __invoke(Request $request)
|
||||
public function __invoke(UploadModuleRequest $request)
|
||||
{
|
||||
$this->authorize('manage modules');
|
||||
|
||||
|
||||
@ -2,24 +2,25 @@
|
||||
|
||||
namespace Crater\Http\Controllers\V1\Admin\Report;
|
||||
|
||||
use PDF;
|
||||
use Carbon\Carbon;
|
||||
use Crater\Http\Controllers\Controller;
|
||||
use Crater\Models\Company;
|
||||
use Crater\Models\CompanySetting;
|
||||
use Crater\Models\Currency;
|
||||
use Crater\Models\Customer;
|
||||
use Illuminate\Http\Request;
|
||||
use Crater\Models\CompanySetting;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use PDF;
|
||||
use Crater\Http\Controllers\Controller;
|
||||
|
||||
class CustomerSalesReportController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $hash
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $hash
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function __invoke(Request $request, $hash)
|
||||
{
|
||||
$company = Company::where('unique_hash', $hash)->first();
|
||||
@ -56,6 +57,7 @@ class CustomerSalesReportController extends Controller
|
||||
$dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id);
|
||||
$from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->format($dateFormat);
|
||||
$to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->format($dateFormat);
|
||||
$currency = Currency::findOrFail(CompanySetting::getSetting('currency', $company->id));
|
||||
|
||||
$colors = [
|
||||
'primary_text_color',
|
||||
@ -80,6 +82,7 @@ class CustomerSalesReportController extends Controller
|
||||
'company' => $company,
|
||||
'from_date' => $from_date,
|
||||
'to_date' => $to_date,
|
||||
'currency' => $currency,
|
||||
]);
|
||||
|
||||
$pdf = PDF::loadView('app.pdf.reports.sales-customers');
|
||||
|
||||
@ -2,24 +2,25 @@
|
||||
|
||||
namespace Crater\Http\Controllers\V1\Admin\Report;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Crater\Http\Controllers\Controller;
|
||||
use Crater\Models\Company;
|
||||
use Crater\Models\CompanySetting;
|
||||
use Crater\Models\Expense;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use PDF;
|
||||
use Carbon\Carbon;
|
||||
use Crater\Models\Company;
|
||||
use Crater\Models\Expense;
|
||||
use Crater\Models\Currency;
|
||||
use Illuminate\Http\Request;
|
||||
use Crater\Models\CompanySetting;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Crater\Http\Controllers\Controller;
|
||||
|
||||
class ExpensesReportController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $hash
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $hash
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function __invoke(Request $request, $hash)
|
||||
{
|
||||
$company = Company::where('unique_hash', $hash)->first();
|
||||
@ -43,6 +44,7 @@ class ExpensesReportController extends Controller
|
||||
$dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id);
|
||||
$from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->format($dateFormat);
|
||||
$to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->format($dateFormat);
|
||||
$currency = Currency::findOrFail(CompanySetting::getSetting('currency', $company->id));
|
||||
|
||||
$colors = [
|
||||
'primary_text_color',
|
||||
@ -66,6 +68,7 @@ class ExpensesReportController extends Controller
|
||||
'company' => $company,
|
||||
'from_date' => $from_date,
|
||||
'to_date' => $to_date,
|
||||
'currency' => $currency,
|
||||
]);
|
||||
$pdf = PDF::loadView('app.pdf.reports.expenses');
|
||||
|
||||
|
||||
@ -2,24 +2,25 @@
|
||||
|
||||
namespace Crater\Http\Controllers\V1\Admin\Report;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Crater\Http\Controllers\Controller;
|
||||
use Crater\Models\Company;
|
||||
use Crater\Models\CompanySetting;
|
||||
use Crater\Models\InvoiceItem;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use PDF;
|
||||
use Carbon\Carbon;
|
||||
use Crater\Models\Company;
|
||||
use Crater\Models\Currency;
|
||||
use Illuminate\Http\Request;
|
||||
use Crater\Models\InvoiceItem;
|
||||
use Crater\Models\CompanySetting;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Crater\Http\Controllers\Controller;
|
||||
|
||||
class ItemSalesReportController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $hash
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $hash
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function __invoke(Request $request, $hash)
|
||||
{
|
||||
$company = Company::where('unique_hash', $hash)->first();
|
||||
@ -43,6 +44,7 @@ class ItemSalesReportController extends Controller
|
||||
$dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id);
|
||||
$from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->format($dateFormat);
|
||||
$to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->format($dateFormat);
|
||||
$currency = Currency::findOrFail(CompanySetting::getSetting('currency', $company->id));
|
||||
|
||||
$colors = [
|
||||
'primary_text_color',
|
||||
@ -66,6 +68,7 @@ class ItemSalesReportController extends Controller
|
||||
'company' => $company,
|
||||
'from_date' => $from_date,
|
||||
'to_date' => $to_date,
|
||||
'currency' => $currency,
|
||||
]);
|
||||
$pdf = PDF::loadView('app.pdf.reports.sales-items');
|
||||
|
||||
|
||||
@ -2,25 +2,26 @@
|
||||
|
||||
namespace Crater\Http\Controllers\V1\Admin\Report;
|
||||
|
||||
use PDF;
|
||||
use Carbon\Carbon;
|
||||
use Crater\Http\Controllers\Controller;
|
||||
use Crater\Models\Company;
|
||||
use Crater\Models\CompanySetting;
|
||||
use Crater\Models\Expense;
|
||||
use Crater\Models\Payment;
|
||||
use Crater\Models\Currency;
|
||||
use Illuminate\Http\Request;
|
||||
use Crater\Models\CompanySetting;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use PDF;
|
||||
use Crater\Http\Controllers\Controller;
|
||||
|
||||
class ProfitLossReportController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $hash
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $hash
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function __invoke(Request $request, $hash)
|
||||
{
|
||||
$company = Company::where('unique_hash', $hash)->first();
|
||||
@ -49,6 +50,8 @@ class ProfitLossReportController extends Controller
|
||||
$dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id);
|
||||
$from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->format($dateFormat);
|
||||
$to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->format($dateFormat);
|
||||
$currency = Currency::findOrFail(CompanySetting::getSetting('currency', $company->id));
|
||||
|
||||
|
||||
$colors = [
|
||||
'primary_text_color',
|
||||
@ -74,6 +77,7 @@ class ProfitLossReportController extends Controller
|
||||
'company' => $company,
|
||||
'from_date' => $from_date,
|
||||
'to_date' => $to_date,
|
||||
'currency' => $currency,
|
||||
]);
|
||||
$pdf = PDF::loadView('app.pdf.reports.profit-loss');
|
||||
|
||||
|
||||
@ -2,24 +2,25 @@
|
||||
|
||||
namespace Crater\Http\Controllers\V1\Admin\Report;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Crater\Http\Controllers\Controller;
|
||||
use Crater\Models\Company;
|
||||
use Crater\Models\CompanySetting;
|
||||
use Crater\Models\Tax;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use PDF;
|
||||
use Carbon\Carbon;
|
||||
use Crater\Models\Tax;
|
||||
use Crater\Models\Company;
|
||||
use Crater\Models\Currency;
|
||||
use Illuminate\Http\Request;
|
||||
use Crater\Models\CompanySetting;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Crater\Http\Controllers\Controller;
|
||||
|
||||
class TaxSummaryReportController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $hash
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $hash
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function __invoke(Request $request, $hash)
|
||||
{
|
||||
$company = Company::where('unique_hash', $hash)->first();
|
||||
@ -44,6 +45,8 @@ class TaxSummaryReportController extends Controller
|
||||
$dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id);
|
||||
$from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->format($dateFormat);
|
||||
$to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->format($dateFormat);
|
||||
$currency = Currency::findOrFail(CompanySetting::getSetting('currency', $company->id));
|
||||
|
||||
|
||||
$colors = [
|
||||
'primary_text_color',
|
||||
@ -68,6 +71,7 @@ class TaxSummaryReportController extends Controller
|
||||
'company' => $company,
|
||||
'from_date' => $from_date,
|
||||
'to_date' => $to_date,
|
||||
'currency' => $currency,
|
||||
]);
|
||||
|
||||
$pdf = PDF::loadView('app.pdf.reports.tax-summary');
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Crater\Http\Controllers\V1\Admin\Settings;
|
||||
|
||||
use Crater\Http\Controllers\Controller;
|
||||
use Crater\Models\Company;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CompanyCurrencyCheckTransactionsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function __invoke(Request $request)
|
||||
{
|
||||
$company = Company::find($request->header('company'));
|
||||
|
||||
$this->authorize('manage company', $company);
|
||||
|
||||
return response()->json([
|
||||
'has_transactions' => $company->hasTransactions(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -3,80 +3,29 @@
|
||||
namespace Crater\Http\Controllers\V1\Admin\Settings;
|
||||
|
||||
use Crater\Http\Controllers\Controller;
|
||||
use Crater\Http\Requests\MailEnvironmentRequest;
|
||||
use Crater\Http\Requests\TestMailDriverRequest;
|
||||
use Crater\Mail\TestMail;
|
||||
use Crater\Models\Setting;
|
||||
use Crater\Space\EnvironmentManager;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Crater\Models\MailSender;
|
||||
use Illuminate\Http\Request;
|
||||
use Mail;
|
||||
|
||||
class MailConfigurationController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var EnvironmentManager
|
||||
*/
|
||||
protected $environmentManager;
|
||||
|
||||
/**
|
||||
* @param EnvironmentManager $environmentManager
|
||||
*/
|
||||
public function __construct(EnvironmentManager $environmentManager)
|
||||
{
|
||||
$this->environmentManager = $environmentManager;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param MailEnvironmentRequest $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function saveMailEnvironment(MailEnvironmentRequest $request)
|
||||
public function TestMailDriver(TestMailDriverRequest $request)
|
||||
{
|
||||
$this->authorize('manage email config');
|
||||
|
||||
$setting = Setting::getSetting('profile_complete');
|
||||
$results = $this->environmentManager->saveMailVariables($request);
|
||||
MailSender::setMailConfiguration($request->mail_sender_id);
|
||||
|
||||
if ($setting !== 'COMPLETED') {
|
||||
Setting::setSetting('profile_complete', 4);
|
||||
}
|
||||
Mail::to($request->to)->send(new TestMail($request->subject, $request->message));
|
||||
|
||||
return response()->json($results);
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function getMailEnvironment()
|
||||
public function getMailDrivers(Request $request)
|
||||
{
|
||||
$this->authorize('manage email config');
|
||||
|
||||
$MailData = [
|
||||
'mail_driver' => config('mail.driver'),
|
||||
'mail_host' => config('mail.host'),
|
||||
'mail_port' => config('mail.port'),
|
||||
'mail_username' => config('mail.username'),
|
||||
'mail_password' => config('mail.password'),
|
||||
'mail_encryption' => config('mail.encryption'),
|
||||
'from_name' => config('mail.from.name'),
|
||||
'from_mail' => config('mail.from.address'),
|
||||
'mail_mailgun_endpoint' => config('services.mailgun.endpoint'),
|
||||
'mail_mailgun_domain' => config('services.mailgun.domain'),
|
||||
'mail_mailgun_secret' => config('services.mailgun.secret'),
|
||||
'mail_ses_key' => config('services.ses.key'),
|
||||
'mail_ses_secret' => config('services.ses.secret'),
|
||||
];
|
||||
|
||||
|
||||
return response()->json($MailData);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function getMailDrivers()
|
||||
{
|
||||
$this->authorize('manage email config');
|
||||
|
||||
$drivers = [
|
||||
'smtp',
|
||||
'mail',
|
||||
@ -87,21 +36,4 @@ class MailConfigurationController extends Controller
|
||||
|
||||
return response()->json($drivers);
|
||||
}
|
||||
|
||||
public function testEmailConfig(Request $request)
|
||||
{
|
||||
$this->authorize('manage email config');
|
||||
|
||||
$this->validate($request, [
|
||||
'to' => 'required|email',
|
||||
'subject' => 'required',
|
||||
'message' => 'required',
|
||||
]);
|
||||
|
||||
Mail::to($request->to)->send(new TestMail($request->subject, $request->message));
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ use Crater\Http\Controllers\Controller;
|
||||
use Crater\Http\Requests\UpdateSettingsRequest;
|
||||
use Crater\Models\Company;
|
||||
use Crater\Models\CompanySetting;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class UpdateCompanySettingsController extends Controller
|
||||
{
|
||||
@ -17,9 +18,23 @@ class UpdateCompanySettingsController extends Controller
|
||||
*/
|
||||
public function __invoke(UpdateSettingsRequest $request)
|
||||
{
|
||||
$this->authorize('manage company', Company::find($request->header('company')));
|
||||
$company = Company::find($request->header('company'));
|
||||
$this->authorize('manage company', $company);
|
||||
|
||||
CompanySetting::setSettings($request->settings, $request->header('company'));
|
||||
$data = $request->settings;
|
||||
|
||||
if (
|
||||
Arr::exists($data, 'currency') &&
|
||||
(CompanySetting::getSetting('currency', $company->id) !== $data['currency']) &&
|
||||
$company->hasTransactions()
|
||||
) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Cannot update company currency after transactions are created.'
|
||||
]);
|
||||
}
|
||||
|
||||
CompanySetting::setSettings($data, $request->header('company'));
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
|
||||
@ -9,6 +9,7 @@ use Crater\Models\CompanySetting;
|
||||
use Crater\Models\Customer;
|
||||
use Crater\Models\EmailLog;
|
||||
use Crater\Models\Estimate;
|
||||
use Crater\Models\MailSender;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class EstimatePdfController extends Controller
|
||||
@ -27,14 +28,16 @@ class EstimatePdfController extends Controller
|
||||
);
|
||||
|
||||
if ($notifyEstimateViewed == 'YES') {
|
||||
$data['estimate'] = Estimate::findOrFail($estimate->id)->toArray();
|
||||
$data['user'] = Customer::find($estimate->customer_id)->toArray();
|
||||
$notificationEmail = CompanySetting::getSetting(
|
||||
'notification_email',
|
||||
$estimate->company_id
|
||||
);
|
||||
$notificationEmail = CompanySetting::getSetting('notification_email', $estimate->company_id);
|
||||
$mailSender = MailSender::where('company_id', $estimate->company_id)->where('is_default', true)->first();
|
||||
MailSender::setMailConfiguration($mailSender->id);
|
||||
|
||||
\Mail::to($notificationEmail)->send(new EstimateViewedMail($data));
|
||||
$data['from_address'] = $mailSender->from_address;
|
||||
$data['from_name'] = $mailSender->from_name;
|
||||
$data['user'] = Customer::find($estimate->customer_id)->toArray();
|
||||
$data['estimate'] = Estimate::findOrFail($estimate->id)->toArray();
|
||||
|
||||
send_mail(new EstimateViewedMail($data), $mailSender, $notificationEmail);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ use Crater\Models\CompanySetting;
|
||||
use Crater\Models\Customer;
|
||||
use Crater\Models\EmailLog;
|
||||
use Crater\Models\Invoice;
|
||||
use Crater\Models\MailSender;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class InvoicePdfController extends Controller
|
||||
@ -28,14 +29,16 @@ class InvoicePdfController extends Controller
|
||||
);
|
||||
|
||||
if ($notifyInvoiceViewed == 'YES') {
|
||||
$notificationEmail = CompanySetting::getSetting('notification_email', $invoice->company_id);
|
||||
$mailSender = MailSender::where('company_id', $invoice->company_id)->where('is_default', true)->first();
|
||||
MailSender::setMailConfiguration($mailSender->id);
|
||||
|
||||
$data['from_address'] = $mailSender->from_address;
|
||||
$data['from_name'] = $mailSender->from_name;
|
||||
$data['invoice'] = Invoice::findOrFail($invoice->id)->toArray();
|
||||
$data['user'] = Customer::find($invoice->customer_id)->toArray();
|
||||
$notificationEmail = CompanySetting::getSetting(
|
||||
'notification_email',
|
||||
$invoice->company_id
|
||||
);
|
||||
|
||||
\Mail::to($notificationEmail)->send(new InvoiceViewedMail($data));
|
||||
send_mail(new InvoiceViewedMail($data), $mailSender, $notificationEmail);
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,8 +47,8 @@ class InvoicePdfController extends Controller
|
||||
}
|
||||
|
||||
return view('app')->with([
|
||||
'customer_logo' => get_customer_logo($invoice->company_id),
|
||||
'current_theme' => get_customer_portal_theme($invoice->company_id)
|
||||
'customer_logo' => get_company_setting('customer_portal_logo', $invoice->company_id),
|
||||
'current_theme' => get_company_setting('customer_portal_theme', $invoice->company_id)
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ namespace Crater\Http\Controllers\V1\PDF;
|
||||
|
||||
use Crater\Http\Controllers\Controller;
|
||||
use Crater\Models\Estimate;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class EstimatePdfController extends Controller
|
||||
{
|
||||
@ -13,8 +14,13 @@ class EstimatePdfController extends Controller
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function __invoke(Estimate $estimate)
|
||||
public function __invoke(Request $request, Estimate $estimate)
|
||||
{
|
||||
if ($request->has('preview')) {
|
||||
return $estimate->getPDFData();
|
||||
}
|
||||
|
||||
|
||||
return $estimate->getGeneratedPDFOrStream('estimate');
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ namespace Crater\Http\Controllers\V1\PDF;
|
||||
|
||||
use Crater\Http\Controllers\Controller;
|
||||
use Crater\Models\Invoice;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class InvoicePdfController extends Controller
|
||||
{
|
||||
@ -13,8 +14,12 @@ class InvoicePdfController extends Controller
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function __invoke(Invoice $invoice)
|
||||
public function __invoke(Request $request, Invoice $invoice)
|
||||
{
|
||||
if ($request->has('preview')) {
|
||||
return $invoice->getPDFData();
|
||||
}
|
||||
|
||||
return $invoice->getGeneratedPDFOrStream('invoice');
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ namespace Crater\Http\Controllers\V1\PDF;
|
||||
|
||||
use Crater\Http\Controllers\Controller;
|
||||
use Crater\Models\Payment;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class PaymentPdfController extends Controller
|
||||
{
|
||||
@ -13,8 +14,12 @@ class PaymentPdfController extends Controller
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function __invoke(Payment $payment)
|
||||
public function __invoke(Request $request, Payment $payment)
|
||||
{
|
||||
if ($request->has('preview')) {
|
||||
return view('app.pdf.payment.payment');
|
||||
}
|
||||
|
||||
return $payment->getGeneratedPDFOrStream('payment');
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
namespace Crater\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Crater\Models\CompanySetting;
|
||||
use Crater\Models\FileDisk;
|
||||
use Crater\Models\MailSender;
|
||||
|
||||
class ConfigMiddleware
|
||||
{
|
||||
@ -18,15 +18,6 @@ class ConfigMiddleware
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
if (\Storage::disk('local')->has('database_created')) {
|
||||
$setting = CompanySetting::getSetting('time_zone', $request->header('company'));
|
||||
|
||||
$timezone = config('app.timezone');
|
||||
|
||||
if ($setting && $setting != null && $setting != $timezone) {
|
||||
config(['app.timezone' => $setting]);
|
||||
date_default_timezone_set($setting);
|
||||
}
|
||||
|
||||
if ($request->has('file_disk_id')) {
|
||||
$file_disk = FileDisk::find($request->file_disk_id);
|
||||
} else {
|
||||
@ -38,6 +29,12 @@ class ConfigMiddleware
|
||||
}
|
||||
}
|
||||
|
||||
$default_mail_sender = MailSender::where('company_id', $request->header('company'))->where('is_default', true)->first();
|
||||
|
||||
if ($default_mail_sender) {
|
||||
$default_mail_sender->setMailConfiguration($default_mail_sender->id);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ class PdfMiddleware
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if (Auth::guard('web')->check() || Auth::guard('api')->check() || Auth::guard('customer')->check()) {
|
||||
if (Auth::guard('web')->check() || Auth::guard('sanctum')->check() || Auth::guard('customer')->check()) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
|
||||
85
app/Http/Requests/MailSenderRequest.php
Normal file
85
app/Http/Requests/MailSenderRequest.php
Normal file
@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace Crater\Http\Requests;
|
||||
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class MailSenderRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'name' => [
|
||||
'required',
|
||||
Rule::unique('mail_senders')
|
||||
->where('company_id', $this->header('company'))
|
||||
],
|
||||
'driver' => [
|
||||
'required',
|
||||
],
|
||||
'is_default' => [
|
||||
'nullable'
|
||||
],
|
||||
'bcc' => [
|
||||
'nullable'
|
||||
],
|
||||
'cc' => [
|
||||
'nullable'
|
||||
],
|
||||
'from_address' => [
|
||||
'nullable'
|
||||
],
|
||||
'from_name' => [
|
||||
'nullable'
|
||||
],
|
||||
'settings' => [
|
||||
'nullable'
|
||||
],
|
||||
'settings.*' => [
|
||||
'nullable'
|
||||
]
|
||||
];
|
||||
|
||||
if ($this->isMethod('PUT')) {
|
||||
$rules['name'] = [
|
||||
'nullable',
|
||||
Rule::unique('mail_senders')
|
||||
->ignore($this->route('mail_sender')->id)
|
||||
->where('company_id', $this->header('company'))
|
||||
];
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
public function getMailSenderPayload()
|
||||
{
|
||||
$data = $this->validated();
|
||||
|
||||
if ($data['settings'] && $data['settings']['encryption'] == 'none') {
|
||||
$data['settings']['encryption'] = '';
|
||||
}
|
||||
|
||||
return collect($data)
|
||||
->merge([
|
||||
'company_id' => $this->header('company'),
|
||||
])
|
||||
->toArray();
|
||||
}
|
||||
}
|
||||
@ -30,7 +30,7 @@ class SendEstimatesRequest extends FormRequest
|
||||
'body' => [
|
||||
'required',
|
||||
],
|
||||
'from' => [
|
||||
'mail_sender_id' => [
|
||||
'required',
|
||||
],
|
||||
'to' => [
|
||||
|
||||
@ -30,7 +30,7 @@ class SendInvoiceRequest extends FormRequest
|
||||
'subject' => [
|
||||
'required',
|
||||
],
|
||||
'from' => [
|
||||
'mail_sender_id' => [
|
||||
'required',
|
||||
],
|
||||
'to' => [
|
||||
|
||||
@ -30,7 +30,7 @@ class SendPaymentRequest extends FormRequest
|
||||
'body' => [
|
||||
'required',
|
||||
],
|
||||
'from' => [
|
||||
'mail_sender_id' => [
|
||||
'required',
|
||||
],
|
||||
'to' => [
|
||||
|
||||
39
app/Http/Requests/TestMailDriverRequest.php
Normal file
39
app/Http/Requests/TestMailDriverRequest.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Crater\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class TestMailDriverRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'to' => [
|
||||
'required',
|
||||
'email'
|
||||
],
|
||||
'subject' => [
|
||||
'required'
|
||||
],
|
||||
'message' => [
|
||||
'required'
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
37
app/Http/Requests/UnzipUpdateRequest.php
Normal file
37
app/Http/Requests/UnzipUpdateRequest.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Crater\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UnzipUpdateRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'path' => [
|
||||
'required',
|
||||
'regex:/^[\.\/\w\-]+$/'
|
||||
],
|
||||
'module' => [
|
||||
'required',
|
||||
'string'
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -25,7 +25,7 @@ class UploadExpenseReceiptRequest extends FormRequest
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'upload_receipt' => [
|
||||
'attachment_receipt' => [
|
||||
'nullable',
|
||||
new Base64Mime(['gif', 'jpg', 'png'])
|
||||
]
|
||||
|
||||
40
app/Http/Requests/UploadModuleRequest.php
Normal file
40
app/Http/Requests/UploadModuleRequest.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Crater\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UploadModuleRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'avatar' => [
|
||||
'required',
|
||||
'file',
|
||||
'mimes:zip',
|
||||
'max:20000'
|
||||
],
|
||||
'module' => [
|
||||
'required',
|
||||
'string',
|
||||
'max:100'
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -51,6 +51,7 @@ class InvoiceResource extends JsonResource
|
||||
'formatted_invoice_date' => $this->formattedInvoiceDate,
|
||||
'formatted_due_date' => $this->formattedDueDate,
|
||||
'payment_module_enabled' => $this->payment_module_enabled,
|
||||
'overdue' => $this->overdue,
|
||||
'items' => $this->when($this->items()->exists(), function () {
|
||||
return InvoiceItemResource::collection($this->items);
|
||||
}),
|
||||
|
||||
@ -55,6 +55,7 @@ class InvoiceResource extends JsonResource
|
||||
'payment_module_enabled' => $this->payment_module_enabled,
|
||||
'sales_tax_type' => $this->sales_tax_type,
|
||||
'sales_tax_address_type' => $this->sales_tax_address_type,
|
||||
'overdue' => $this->overdue,
|
||||
'items' => $this->when($this->items()->exists(), function () {
|
||||
return InvoiceItemResource::collection($this->items);
|
||||
}),
|
||||
|
||||
30
app/Http/Resources/MailSenderResource.php
Normal file
30
app/Http/Resources/MailSenderResource.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Crater\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class MailSenderResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'name' => $this->name,
|
||||
'driver' => $this->driver,
|
||||
'is_default' => $this->is_default,
|
||||
'bcc' => $this->bcc,
|
||||
'cc' => $this->cc,
|
||||
'from_address' => $this->from_address,
|
||||
'from_name' => $this->from_name,
|
||||
'company_id' => $this->company_id,
|
||||
'settings' => $this->settings
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -30,7 +30,7 @@ class EstimateViewedMail extends Mailable
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
return $this->from(config('mail.from.address'), config('mail.from.name'))
|
||||
return $this->from($this->data['from_address'], $this->data['from_name'])
|
||||
->markdown('emails.viewed.estimate', ['data', $this->data]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ class InvoiceViewedMail extends Mailable
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
return $this->from(config('mail.from.address'), config('mail.from.name'))
|
||||
return $this->from($this->data['from_address'], $this->data['from_name'])
|
||||
->markdown('emails.viewed.invoice', ['data', $this->data]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ class SendEstimateMail extends Mailable
|
||||
public function build()
|
||||
{
|
||||
$log = EmailLog::create([
|
||||
'from' => $this->data['from'],
|
||||
'from' => $this->data['from_address'],
|
||||
'to' => $this->data['to'],
|
||||
'subject' => $this->data['subject'],
|
||||
'body' => $this->data['body'],
|
||||
@ -47,9 +47,10 @@ class SendEstimateMail extends Mailable
|
||||
|
||||
$this->data['url'] = route('estimate', ['email_log' => $log->token]);
|
||||
|
||||
$mailContent = $this->from($this->data['from'], config('mail.from.name'))
|
||||
->subject($this->data['subject'])
|
||||
->markdown('emails.send.estimate', ['data', $this->data]);
|
||||
$mailContent = $this->from($this->data['from_address'], $this->data['from_name'])
|
||||
->subject($this->data['subject'])
|
||||
->markdown("emails.send.estimate", ['data', $this->data]);
|
||||
|
||||
|
||||
if ($this->data['attach']['data']) {
|
||||
$mailContent->attachData(
|
||||
|
||||
@ -34,7 +34,7 @@ class SendInvoiceMail extends Mailable
|
||||
public function build()
|
||||
{
|
||||
$log = EmailLog::create([
|
||||
'from' => $this->data['from'],
|
||||
'from' => $this->data['from_address'],
|
||||
'to' => $this->data['to'],
|
||||
'subject' => $this->data['subject'],
|
||||
'body' => $this->data['body'],
|
||||
@ -47,9 +47,9 @@ class SendInvoiceMail extends Mailable
|
||||
|
||||
$this->data['url'] = route('invoice', ['email_log' => $log->token]);
|
||||
|
||||
$mailContent = $this->from($this->data['from'], config('mail.from.name'))
|
||||
$mailContent = $this->from($this->data['from_address'], $this->data['from_name'])
|
||||
->subject($this->data['subject'])
|
||||
->markdown('emails.send.invoice', ['data', $this->data]);
|
||||
->markdown("emails.send.invoice", ['data', $this->data]);
|
||||
|
||||
if ($this->data['attach']['data']) {
|
||||
$mailContent->attachData(
|
||||
|
||||
@ -34,7 +34,7 @@ class SendPaymentMail extends Mailable
|
||||
public function build()
|
||||
{
|
||||
$log = EmailLog::create([
|
||||
'from' => $this->data['from'],
|
||||
'from' => $this->data['from_address'],
|
||||
'to' => $this->data['to'],
|
||||
'subject' => $this->data['subject'],
|
||||
'body' => $this->data['body'],
|
||||
@ -47,9 +47,9 @@ class SendPaymentMail extends Mailable
|
||||
|
||||
$this->data['url'] = route('payment', ['email_log' => $log->token]);
|
||||
|
||||
$mailContent = $this->from($this->data['from'], config('mail.from.name'))
|
||||
->subject($this->data['subject'])
|
||||
->markdown('emails.send.payment', ['data', $this->data]);
|
||||
$mailContent = $this->from($this->data['from_address'], $this->data['from_name'])
|
||||
->subject($this->data['subject'])
|
||||
->markdown("emails.send.payment", ['data', $this->data]);
|
||||
|
||||
if ($this->data['attach']['data']) {
|
||||
$mailContent->attachData(
|
||||
|
||||
@ -217,7 +217,7 @@ class Company extends Model implements HasMedia
|
||||
'estimate_billing_address_format' => $billingAddressFormat,
|
||||
'payment_company_address_format' => $companyAddressFormat,
|
||||
'payment_from_customer_address_format' => $paymentFromCustomerAddress,
|
||||
'currency' => request()->currency ?? 12,
|
||||
'currency' => request()->currency ?? 13,
|
||||
'time_zone' => 'Asia/Kolkata',
|
||||
'language' => 'en',
|
||||
'fiscal_year' => '1-12',
|
||||
@ -300,6 +300,10 @@ class Company extends Model implements HasMedia
|
||||
if ($this->invoices()->exists()) {
|
||||
$this->invoices->map(function ($invoice) {
|
||||
$this->checkModelData($invoice);
|
||||
|
||||
if ($invoice->transactions()->exists()) {
|
||||
$invoice->transactions()->delete();
|
||||
}
|
||||
});
|
||||
|
||||
$this->invoices()->delete();
|
||||
@ -376,4 +380,21 @@ class Company extends Model implements HasMedia
|
||||
$model->taxes()->delete();
|
||||
}
|
||||
}
|
||||
|
||||
public function hasTransactions()
|
||||
{
|
||||
if (
|
||||
$this->customers()->exists() ||
|
||||
$this->items()->exists() ||
|
||||
$this->invoices()->exists() ||
|
||||
$this->estimates()->exists() ||
|
||||
$this->expenses()->exists() ||
|
||||
$this->payments()->exists() ||
|
||||
$this->recurringInvoices()->exists()
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,7 +139,12 @@ class Customer extends Authenticatable implements HasMedia
|
||||
}
|
||||
|
||||
if ($customer->invoices()->exists()) {
|
||||
$customer->invoices()->delete();
|
||||
$customer->invoices->map(function ($invoice) {
|
||||
if ($invoice->transactions()->exists()) {
|
||||
$invoice->transactions()->delete();
|
||||
}
|
||||
$invoice->delete();
|
||||
});
|
||||
}
|
||||
|
||||
if ($customer->payments()->exists()) {
|
||||
|
||||
@ -5,10 +5,10 @@ namespace Crater\Models;
|
||||
use App;
|
||||
use Barryvdh\DomPDF\Facade as PDF;
|
||||
use Carbon\Carbon;
|
||||
use Crater\Mail\SendEstimateMail;
|
||||
use Crater\Services\SerialNumberFormatter;
|
||||
use Crater\Traits\GeneratesPdfTrait;
|
||||
use Crater\Traits\HasCustomFieldsTrait;
|
||||
use Crater\Traits\MailTrait;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
@ -20,6 +20,7 @@ use Vinkla\Hashids\Facades\Hashids;
|
||||
class Estimate extends Model implements HasMedia
|
||||
{
|
||||
use HasFactory;
|
||||
use MailTrait;
|
||||
use InteractsWithMedia;
|
||||
use GeneratesPdfTrait;
|
||||
use HasCustomFieldsTrait;
|
||||
@ -363,7 +364,7 @@ class Estimate extends Model implements HasMedia
|
||||
$this->save();
|
||||
}
|
||||
|
||||
\Mail::to($data['to'])->send(new SendEstimateMail($data));
|
||||
$this->setMail('estimate', $data);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
@ -412,6 +413,10 @@ class Estimate extends Model implements HasMedia
|
||||
'taxes' => $taxes,
|
||||
]);
|
||||
|
||||
if (request()->has('preview')) {
|
||||
return view('app.pdf.estimate.'.$estimateTemplate);
|
||||
}
|
||||
|
||||
return PDF::loadView('app.pdf.estimate.'.$estimateTemplate);
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ use Crater\Mail\SendInvoiceMail;
|
||||
use Crater\Services\SerialNumberFormatter;
|
||||
use Crater\Traits\GeneratesPdfTrait;
|
||||
use Crater\Traits\HasCustomFieldsTrait;
|
||||
use Crater\Traits\MailTrait;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
@ -21,6 +22,7 @@ use Vinkla\Hashids\Facades\Hashids;
|
||||
class Invoice extends Model implements HasMedia
|
||||
{
|
||||
use HasFactory;
|
||||
use MailTrait;
|
||||
use InteractsWithMedia;
|
||||
use GeneratesPdfTrait;
|
||||
use HasCustomFieldsTrait;
|
||||
@ -28,10 +30,8 @@ class Invoice extends Model implements HasMedia
|
||||
public const STATUS_DRAFT = 'DRAFT';
|
||||
public const STATUS_SENT = 'SENT';
|
||||
public const STATUS_VIEWED = 'VIEWED';
|
||||
public const STATUS_OVERDUE = 'OVERDUE';
|
||||
public const STATUS_COMPLETED = 'COMPLETED';
|
||||
|
||||
public const STATUS_DUE = 'DUE';
|
||||
public const STATUS_UNPAID = 'UNPAID';
|
||||
public const STATUS_PARTIALLY_PAID = 'PARTIALLY_PAID';
|
||||
public const STATUS_PAID = 'PAID';
|
||||
@ -138,7 +138,6 @@ class Invoice extends Model implements HasMedia
|
||||
self::STATUS_DRAFT,
|
||||
self::STATUS_SENT,
|
||||
self::STATUS_VIEWED,
|
||||
self::STATUS_OVERDUE,
|
||||
self::STATUS_COMPLETED,
|
||||
];
|
||||
|
||||
@ -155,9 +154,7 @@ class Invoice extends Model implements HasMedia
|
||||
|
||||
public function getPreviousStatus()
|
||||
{
|
||||
if ($this->due_date < Carbon::now()) {
|
||||
return self::STATUS_OVERDUE;
|
||||
} elseif ($this->viewed) {
|
||||
if ($this->viewed) {
|
||||
return self::STATUS_VIEWED;
|
||||
} elseif ($this->sent) {
|
||||
return self::STATUS_SENT;
|
||||
@ -254,7 +251,7 @@ class Invoice extends Model implements HasMedia
|
||||
$filters->get('status') == self::STATUS_PAID
|
||||
) {
|
||||
$query->wherePaidStatus($filters->get('status'));
|
||||
} elseif ($filters->get('status') == self::STATUS_DUE) {
|
||||
} elseif ($filters->get('status') == 'DUE') {
|
||||
$query->whereDueStatus($filters->get('status'));
|
||||
} else {
|
||||
$query->whereStatus($filters->get('status'));
|
||||
@ -448,7 +445,8 @@ class Invoice extends Model implements HasMedia
|
||||
$data['invoice'] = $this->toArray();
|
||||
$data['customer'] = $this->customer->toArray();
|
||||
$data['company'] = Company::find($this->company_id);
|
||||
$data['body'] = $this->getEmailBody($data['body']);
|
||||
$data['subject'] = $this->getEmailString($data['subject']);
|
||||
$data['body'] = $this->getEmailString($data['body']);
|
||||
$data['attach']['data'] = ($this->getEmailAttachmentSetting()) ? $this->getPDFData() : null;
|
||||
|
||||
return $data;
|
||||
@ -468,7 +466,7 @@ class Invoice extends Model implements HasMedia
|
||||
{
|
||||
$data = $this->sendInvoiceData($data);
|
||||
|
||||
\Mail::to($data['to'])->send(new SendInvoiceMail($data));
|
||||
$this->setMail('invoice', $data);
|
||||
|
||||
if ($this->status == Invoice::STATUS_DRAFT) {
|
||||
$this->status = Invoice::STATUS_SENT;
|
||||
@ -503,6 +501,10 @@ class Invoice extends Model implements HasMedia
|
||||
if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) {
|
||||
foreach ($invoiceItem['taxes'] as $tax) {
|
||||
$tax['company_id'] = $invoice->company_id;
|
||||
$tax['exchange_rate'] = $invoice->exchange_rate;
|
||||
$tax['base_amount'] = $tax['amount'] * $exchange_rate;
|
||||
$tax['currency_id'] = $invoice->currency_id;
|
||||
|
||||
if (gettype($tax['amount']) !== "NULL") {
|
||||
if (array_key_exists('recurring_invoice_id', $invoiceItem)) {
|
||||
unset($invoiceItem['recurring_invoice_id']);
|
||||
@ -525,7 +527,7 @@ class Invoice extends Model implements HasMedia
|
||||
|
||||
foreach ($taxes as $tax) {
|
||||
$tax['company_id'] = $invoice->company_id;
|
||||
$tax['exchnage_rate'] = $invoice->exchange_rate;
|
||||
$tax['exchange_rate'] = $invoice->exchange_rate;
|
||||
$tax['base_amount'] = $tax['amount'] * $exchange_rate;
|
||||
$tax['currency_id'] = $invoice->currency_id;
|
||||
|
||||
@ -580,6 +582,10 @@ class Invoice extends Model implements HasMedia
|
||||
'taxes' => $taxes,
|
||||
]);
|
||||
|
||||
if (request()->has('preview')) {
|
||||
return view('app.pdf.invoice.'.$invoiceTemplate);
|
||||
}
|
||||
|
||||
return PDF::loadView('app.pdf.invoice.'.$invoiceTemplate);
|
||||
}
|
||||
|
||||
@ -632,7 +638,7 @@ class Invoice extends Model implements HasMedia
|
||||
return $this->getFormattedString($this->notes);
|
||||
}
|
||||
|
||||
public function getEmailBody($body)
|
||||
public function getEmailString($body)
|
||||
{
|
||||
$values = array_merge($this->getFieldsArray(), $this->getExtraFields());
|
||||
|
||||
@ -692,6 +698,7 @@ class Invoice extends Model implements HasMedia
|
||||
if ($amount == 0) {
|
||||
$this->status = Invoice::STATUS_COMPLETED;
|
||||
$this->paid_status = Invoice::STATUS_PAID;
|
||||
$this->overdue = false;
|
||||
} elseif ($amount == $this->total) {
|
||||
$this->status = $this->getPreviousStatus();
|
||||
$this->paid_status = Invoice::STATUS_UNPAID;
|
||||
|
||||
111
app/Models/MailSender.php
Normal file
111
app/Models/MailSender.php
Normal file
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace Crater\Models;
|
||||
|
||||
use Crater\Http\Requests\MailSenderRequest;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Config;
|
||||
|
||||
class MailSender extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $guarded = [
|
||||
'id'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'settings' => 'array',
|
||||
'is_default' => 'boolean'
|
||||
];
|
||||
|
||||
public function company()
|
||||
{
|
||||
return $this->belongsTo(Company::class);
|
||||
}
|
||||
|
||||
public function scopeWhereOrder($query, $orderByField, $orderBy)
|
||||
{
|
||||
$query->orderBy($orderByField, $orderBy);
|
||||
}
|
||||
|
||||
public function scopeApplyFilters($query, array $filters)
|
||||
{
|
||||
$filters = collect($filters);
|
||||
|
||||
if ($filters->get('orderByField') || $filters->get('orderBy')) {
|
||||
$field = $filters->get('orderByField') ? $filters->get('orderByField') : 'name';
|
||||
$orderBy = $filters->get('orderBy') ? $filters->get('orderBy') : 'desc';
|
||||
$query->whereOrder($field, $orderBy);
|
||||
}
|
||||
}
|
||||
|
||||
public function scopePaginateData($query, $limit)
|
||||
{
|
||||
if ($limit == 'all') {
|
||||
return $query->get();
|
||||
}
|
||||
|
||||
return $query->paginate($limit);
|
||||
}
|
||||
|
||||
public function scopeWhereCompany($query)
|
||||
{
|
||||
$query->where('mail_senders.company_id', request()->header('company'));
|
||||
}
|
||||
|
||||
public static function createFromRequest(MailSenderRequest $request)
|
||||
{
|
||||
$senderMail = self::create($request->getMailSenderPayload());
|
||||
|
||||
if ($request->is_default) {
|
||||
$senderMail->removeOtherDefaultMailSenders($request);
|
||||
}
|
||||
|
||||
return $senderMail;
|
||||
}
|
||||
|
||||
public function updateFromRequest(MailSenderRequest $request)
|
||||
{
|
||||
$data = $request->getMailSenderPayload();
|
||||
|
||||
$this->update($data);
|
||||
|
||||
if ($request->is_default) {
|
||||
$this->removeOtherDefaultMailSenders($request);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public static function setMailConfiguration($id, $check = null)
|
||||
{
|
||||
$mailSender = MailSender::find($id);
|
||||
|
||||
$settings = $mailSender->settings;
|
||||
$settings['driver'] = $mailSender->driver;
|
||||
$settings['from'] = [
|
||||
'address' => $mailSender->from_address,
|
||||
'name' => $mailSender->from_name
|
||||
];
|
||||
$settings['sendmail'] = config('mail.sendmail');
|
||||
$settings['markdown'] = config('mail.markdown');
|
||||
$settings['log_channel'] = config('mail.log_channel');
|
||||
|
||||
Config::set('mail', $settings);
|
||||
|
||||
if ($check) {
|
||||
return $mailSender;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function removeOtherDefaultMailSenders($request) {
|
||||
MailSender::where('company_id', $request->header('company'))
|
||||
->where('is_default', true)
|
||||
->where('id', '<>', $this->id)
|
||||
->update(['is_default' => false]);
|
||||
}
|
||||
}
|
||||
@ -5,10 +5,10 @@ namespace Crater\Models;
|
||||
use Barryvdh\DomPDF\Facade as PDF;
|
||||
use Carbon\Carbon;
|
||||
use Crater\Jobs\GeneratePaymentPdfJob;
|
||||
use Crater\Mail\SendPaymentMail;
|
||||
use Crater\Services\SerialNumberFormatter;
|
||||
use Crater\Traits\GeneratesPdfTrait;
|
||||
use Crater\Traits\HasCustomFieldsTrait;
|
||||
use Crater\Traits\MailTrait;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Spatie\MediaLibrary\HasMedia;
|
||||
@ -18,6 +18,7 @@ use Vinkla\Hashids\Facades\Hashids;
|
||||
class Payment extends Model implements HasMedia
|
||||
{
|
||||
use HasFactory;
|
||||
use MailTrait;
|
||||
use InteractsWithMedia;
|
||||
use GeneratesPdfTrait;
|
||||
use HasCustomFieldsTrait;
|
||||
@ -135,7 +136,7 @@ class Payment extends Model implements HasMedia
|
||||
{
|
||||
$data = $this->sendPaymentData($data);
|
||||
|
||||
\Mail::to($data['to'])->send(new SendPaymentMail($data));
|
||||
$this->setMail('payment', $data);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
@ -375,6 +376,10 @@ class Payment extends Model implements HasMedia
|
||||
'logo' => $logo ?? null,
|
||||
]);
|
||||
|
||||
if (request()->has('preview')) {
|
||||
return view('app.pdf.payment.payment');
|
||||
}
|
||||
|
||||
return PDF::loadView('app.pdf.payment.payment');
|
||||
}
|
||||
|
||||
|
||||
@ -305,9 +305,15 @@ class RecurringInvoice extends Model
|
||||
->setCustomer($this->customer_id)
|
||||
->setNextNumbers();
|
||||
|
||||
$days = CompanySetting::getSetting('invoice_due_date_days', $this->company_id);
|
||||
|
||||
if (! $days || $days == "null") {
|
||||
$days = 7;
|
||||
}
|
||||
|
||||
$newInvoice['creator_id'] = $this->creator_id;
|
||||
$newInvoice['invoice_date'] = Carbon::today()->format('Y-m-d');
|
||||
$newInvoice['due_date'] = Carbon::today()->addDays(7)->format('Y-m-d');
|
||||
$newInvoice['due_date'] = Carbon::today()->addDays($days)->format('Y-m-d');
|
||||
$newInvoice['status'] = Invoice::STATUS_DRAFT;
|
||||
$newInvoice['company_id'] = $this->company_id;
|
||||
$newInvoice['paid_status'] = Invoice::STATUS_UNPAID;
|
||||
|
||||
123
app/Policies/MailSenderPolicy.php
Normal file
123
app/Policies/MailSenderPolicy.php
Normal file
@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
namespace Crater\Policies;
|
||||
|
||||
use Crater\Models\MailSender;
|
||||
use Crater\Models\User;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
use Silber\Bouncer\BouncerFacade;
|
||||
|
||||
class MailSenderPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*
|
||||
* @param \Crater\Models\User $user
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function viewAny(User $user)
|
||||
{
|
||||
if (BouncerFacade::can('view-mail-sender', MailSender::class)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*
|
||||
* @param \Crater\Models\User $user
|
||||
* @param \Crater\Models\MailSender $mailSender
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function view(User $user, MailSender $mailSender)
|
||||
{
|
||||
if (BouncerFacade::can('view-mail-sender', $mailSender) && $user->hasCompany($mailSender->company_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create models.
|
||||
*
|
||||
* @param \Crater\Models\User $user
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function create(User $user)
|
||||
{
|
||||
if (BouncerFacade::can('create-mail-sender', MailSender::class)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*
|
||||
* @param \Crater\Models\User $user
|
||||
* @param \Crater\Models\MailSender $mailSender
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function update(User $user, MailSender $mailSender)
|
||||
{
|
||||
if (BouncerFacade::can('edit-mail-sender', $mailSender) && $user->hasCompany($mailSender->company_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*
|
||||
* @param \Crater\Models\User $user
|
||||
* @param \Crater\Models\MailSender $mailSender
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function delete(User $user, MailSender $mailSender)
|
||||
{
|
||||
if (BouncerFacade::can('delete-mail-sender', $mailSender) && $user->hasCompany($mailSender->company_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore the model.
|
||||
*
|
||||
* @param \Crater\Models\User $user
|
||||
* @param \Crater\Models\MailSender $mailSender
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function restore(User $user, MailSender $mailSender)
|
||||
{
|
||||
if (BouncerFacade::can('delete-mail-sender', $mailSender) && $user->hasCompany($mailSender->company_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently delete the model.
|
||||
*
|
||||
* @param \Crater\Models\User $user
|
||||
* @param \Crater\Models\MailSender $mailSender
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function forceDelete(User $user, MailSender $mailSender)
|
||||
{
|
||||
if (BouncerFacade::can('delete-mail-sender', $mailSender) && $user->hasCompany($mailSender->company_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -39,6 +39,7 @@ class AuthServiceProvider extends ServiceProvider
|
||||
\Crater\Models\CustomField::class => \Crater\Policies\CustomFieldPolicy::class,
|
||||
\Crater\Models\User::class => \Crater\Policies\UserPolicy::class,
|
||||
\Crater\Models\Item::class => \Crater\Policies\ItemPolicy::class,
|
||||
\Crater\Models\MailSender::class => \Crater\Policies\MailSenderPolicy::class,
|
||||
\Silber\Bouncer\Database\Role::class => \Crater\Policies\RolePolicy::class,
|
||||
\Crater\Models\Unit::class => \Crater\Policies\UnitPolicy::class,
|
||||
\Crater\Models\RecurringInvoice::class => \Crater\Policies\RecurringInvoicePolicy::class,
|
||||
|
||||
@ -26,9 +26,11 @@ class ViewServiceProvider extends ServiceProvider
|
||||
public function boot()
|
||||
{
|
||||
if (\Storage::disk('local')->has('database_created') && Schema::hasTable('settings')) {
|
||||
View::share('login_page_logo', get_login_page_logo());
|
||||
View::share('login_page_heading', get_login_page_heading());
|
||||
View::share('login_page_description', get_login_page_description());
|
||||
View::share('login_page_logo', get_app_setting('login_page_logo'));
|
||||
View::share('login_page_heading', get_app_setting('login_page_heading'));
|
||||
View::share('login_page_description', get_app_setting('login_page_description'));
|
||||
View::share('admin_page_title', get_app_setting('admin_page_title'));
|
||||
View::share('copyright_text', get_app_setting('copyright_text'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -223,204 +223,6 @@ class EnvironmentManager
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the mail content to the .env file.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function saveMailVariables(MailEnvironmentRequest $request)
|
||||
{
|
||||
$mailData = $this->getMailData($request);
|
||||
|
||||
try {
|
||||
file_put_contents($this->envPath, str_replace(
|
||||
$mailData['old_mail_data'],
|
||||
$mailData['new_mail_data'],
|
||||
file_get_contents($this->envPath)
|
||||
));
|
||||
|
||||
if ($mailData['extra_old_mail_data']) {
|
||||
file_put_contents($this->envPath, str_replace(
|
||||
$mailData['extra_old_mail_data'],
|
||||
$mailData['extra_mail_data'],
|
||||
file_get_contents($this->envPath)
|
||||
));
|
||||
} else {
|
||||
file_put_contents(
|
||||
$this->envPath,
|
||||
"\n".$mailData['extra_mail_data'],
|
||||
FILE_APPEND
|
||||
);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'error' => 'mail_variables_save_error',
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => 'mail_variables_save_successfully',
|
||||
];
|
||||
}
|
||||
|
||||
private function getMailData($request)
|
||||
{
|
||||
$mailFromCredential = "";
|
||||
$extraMailData = "";
|
||||
$extraOldMailData = "";
|
||||
$oldMailData = "";
|
||||
$newMailData = "";
|
||||
|
||||
if (env('MAIL_FROM_ADDRESS') !== null && env('MAIL_FROM_NAME') !== null) {
|
||||
$mailFromCredential =
|
||||
'MAIL_FROM_ADDRESS='.config('mail.from.address')."\n".
|
||||
'MAIL_FROM_NAME="'.config('mail.from.name')."\"\n\n";
|
||||
}
|
||||
|
||||
switch ($request->mail_driver) {
|
||||
case 'smtp':
|
||||
|
||||
$oldMailData =
|
||||
'MAIL_DRIVER='.config('mail.driver')."\n".
|
||||
'MAIL_HOST='.config('mail.host')."\n".
|
||||
'MAIL_PORT='.config('mail.port')."\n".
|
||||
'MAIL_USERNAME='.config('mail.username')."\n".
|
||||
'MAIL_PASSWORD='.config('mail.password')."\n".
|
||||
'MAIL_ENCRYPTION='.config('mail.encryption')."\n\n".
|
||||
$mailFromCredential;
|
||||
|
||||
$newMailData =
|
||||
'MAIL_DRIVER='.$request->mail_driver."\n".
|
||||
'MAIL_HOST='.$request->mail_host."\n".
|
||||
'MAIL_PORT='.$request->mail_port."\n".
|
||||
'MAIL_USERNAME='.$request->mail_username."\n".
|
||||
'MAIL_PASSWORD='.$request->mail_password."\n".
|
||||
'MAIL_ENCRYPTION='.$request->mail_encryption."\n\n".
|
||||
'MAIL_FROM_ADDRESS='.$request->from_mail."\n".
|
||||
'MAIL_FROM_NAME="'.$request->from_name."\"\n\n";
|
||||
|
||||
break;
|
||||
|
||||
case 'mailgun':
|
||||
$oldMailData =
|
||||
'MAIL_DRIVER='.config('mail.driver')."\n".
|
||||
'MAIL_HOST='.config('mail.host')."\n".
|
||||
'MAIL_PORT='.config('mail.port')."\n".
|
||||
'MAIL_USERNAME='.config('mail.username')."\n".
|
||||
'MAIL_PASSWORD='.config('mail.password')."\n".
|
||||
'MAIL_ENCRYPTION='.config('mail.encryption')."\n\n".
|
||||
$mailFromCredential;
|
||||
|
||||
$newMailData =
|
||||
'MAIL_DRIVER='.$request->mail_driver."\n".
|
||||
'MAIL_HOST='.$request->mail_host."\n".
|
||||
'MAIL_PORT='.$request->mail_port."\n".
|
||||
'MAIL_USERNAME='.config('mail.username')."\n".
|
||||
'MAIL_PASSWORD='.config('mail.password')."\n".
|
||||
'MAIL_ENCRYPTION='.$request->mail_encryption."\n\n".
|
||||
'MAIL_FROM_ADDRESS='.$request->from_mail."\n".
|
||||
'MAIL_FROM_NAME="'.$request->from_name."\"\n\n";
|
||||
|
||||
$extraMailData =
|
||||
'MAILGUN_DOMAIN='.$request->mail_mailgun_domain."\n".
|
||||
'MAILGUN_SECRET='.$request->mail_mailgun_secret."\n".
|
||||
'MAILGUN_ENDPOINT='.$request->mail_mailgun_endpoint."\n";
|
||||
|
||||
if (env('MAILGUN_DOMAIN') !== null && env('MAILGUN_SECRET') !== null && env('MAILGUN_ENDPOINT') !== null) {
|
||||
$extraOldMailData =
|
||||
'MAILGUN_DOMAIN='.config('services.mailgun.domain')."\n".
|
||||
'MAILGUN_SECRET='.config('services.mailgun.secret')."\n".
|
||||
'MAILGUN_ENDPOINT='.config('services.mailgun.endpoint')."\n";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'ses':
|
||||
$oldMailData =
|
||||
'MAIL_DRIVER='.config('mail.driver')."\n".
|
||||
'MAIL_HOST='.config('mail.host')."\n".
|
||||
'MAIL_PORT='.config('mail.port')."\n".
|
||||
'MAIL_USERNAME='.config('mail.username')."\n".
|
||||
'MAIL_PASSWORD='.config('mail.password')."\n".
|
||||
'MAIL_ENCRYPTION='.config('mail.encryption')."\n\n".
|
||||
$mailFromCredential;
|
||||
|
||||
$newMailData =
|
||||
'MAIL_DRIVER='.$request->mail_driver."\n".
|
||||
'MAIL_HOST='.$request->mail_host."\n".
|
||||
'MAIL_PORT='.$request->mail_port."\n".
|
||||
'MAIL_USERNAME='.config('mail.username')."\n".
|
||||
'MAIL_PASSWORD='.config('mail.password')."\n".
|
||||
'MAIL_ENCRYPTION='.$request->mail_encryption."\n\n".
|
||||
'MAIL_FROM_ADDRESS='.$request->from_mail."\n".
|
||||
'MAIL_FROM_NAME="'.$request->from_name."\"\n\n";
|
||||
|
||||
$extraMailData =
|
||||
'SES_KEY='.$request->mail_ses_key."\n".
|
||||
'SES_SECRET='.$request->mail_ses_secret."\n";
|
||||
|
||||
if (env('SES_KEY') !== null && env('SES_SECRET') !== null) {
|
||||
$extraOldMailData =
|
||||
'SES_KEY='.config('services.ses.key')."\n".
|
||||
'SES_SECRET='.config('services.ses.secret')."\n";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'mail':
|
||||
$oldMailData =
|
||||
'MAIL_DRIVER='.config('mail.driver')."\n".
|
||||
'MAIL_HOST='.config('mail.host')."\n".
|
||||
'MAIL_PORT='.config('mail.port')."\n".
|
||||
'MAIL_USERNAME='.config('mail.username')."\n".
|
||||
'MAIL_PASSWORD='.config('mail.password')."\n".
|
||||
'MAIL_ENCRYPTION='.config('mail.encryption')."\n\n".
|
||||
$mailFromCredential;
|
||||
|
||||
$newMailData =
|
||||
'MAIL_DRIVER='.$request->mail_driver."\n".
|
||||
'MAIL_HOST='.config('mail.host')."\n".
|
||||
'MAIL_PORT='.config('mail.port')."\n".
|
||||
'MAIL_USERNAME='.config('mail.username')."\n".
|
||||
'MAIL_PASSWORD='.config('mail.password')."\n".
|
||||
'MAIL_ENCRYPTION='.config('mail.encryption')."\n\n".
|
||||
'MAIL_FROM_ADDRESS='.$request->from_mail."\n".
|
||||
'MAIL_FROM_NAME="'.$request->from_name."\"\n\n";
|
||||
|
||||
break;
|
||||
|
||||
case 'sendmail':
|
||||
$oldMailData =
|
||||
'MAIL_DRIVER='.config('mail.driver')."\n".
|
||||
'MAIL_HOST='.config('mail.host')."\n".
|
||||
'MAIL_PORT='.config('mail.port')."\n".
|
||||
'MAIL_USERNAME='.config('mail.username')."\n".
|
||||
'MAIL_PASSWORD='.config('mail.password')."\n".
|
||||
'MAIL_ENCRYPTION='.config('mail.encryption')."\n\n".
|
||||
$mailFromCredential;
|
||||
|
||||
$newMailData =
|
||||
'MAIL_DRIVER='.$request->mail_driver."\n".
|
||||
'MAIL_HOST='.config('mail.host')."\n".
|
||||
'MAIL_PORT='.config('mail.port')."\n".
|
||||
'MAIL_USERNAME='.config('mail.username')."\n".
|
||||
'MAIL_PASSWORD='.config('mail.password')."\n".
|
||||
'MAIL_ENCRYPTION='.config('mail.encryption')."\n\n".
|
||||
'MAIL_FROM_ADDRESS='.$request->from_mail."\n".
|
||||
'MAIL_FROM_NAME="'.$request->from_name."\"\n\n";
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return [
|
||||
'old_mail_data' => $oldMailData,
|
||||
'new_mail_data' => $newMailData,
|
||||
'extra_mail_data' => $extraMailData,
|
||||
'extra_old_mail_data' => $extraOldMailData,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the disk content to the .env file.
|
||||
*
|
||||
|
||||
@ -5,95 +5,60 @@ use Crater\Models\Currency;
|
||||
use Crater\Models\CustomField;
|
||||
use Crater\Models\Setting;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Mail\Mailable;
|
||||
|
||||
/**
|
||||
* Get current customer theme
|
||||
* Get company setting
|
||||
*
|
||||
* @param $company_id
|
||||
* @return string
|
||||
*/
|
||||
function get_customer_portal_theme($company_id)
|
||||
function get_company_setting($key, $company_id)
|
||||
{
|
||||
if (\Storage::disk('local')->has('database_created')) {
|
||||
return CompanySetting::getSetting('customer_portal_theme', $company_id);
|
||||
return CompanySetting::getSetting($key, $company_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get current customer logo
|
||||
* Get app setting
|
||||
*
|
||||
* @param $company_id
|
||||
* @return string
|
||||
*/
|
||||
function get_customer_logo($company_id)
|
||||
function get_app_setting($key)
|
||||
{
|
||||
if (\Storage::disk('local')->has('database_created')) {
|
||||
return CompanySetting::getSetting('customer_portal_logo', $company_id);
|
||||
return Setting::getSetting($key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get current admin portal logo
|
||||
* Get page title
|
||||
*
|
||||
* @param $company_id
|
||||
* @return string
|
||||
*/
|
||||
function get_login_page_logo()
|
||||
function get_page_title($company_id)
|
||||
{
|
||||
if (\Storage::disk('local')->has('database_created')) {
|
||||
return Setting::getSetting('login_page_logo');
|
||||
}
|
||||
}
|
||||
$routeName = Route::currentRouteName();
|
||||
|
||||
/**
|
||||
* Get current admin theme
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function get_admin_portal_theme()
|
||||
{
|
||||
if (\Storage::disk('local')->has('database_created')) {
|
||||
$setting = Setting::getSetting('admin_portal_theme');
|
||||
$pageTitle = null;
|
||||
$defaultPageTitle = 'Crater - Self Hosted Invoicing Platform';
|
||||
|
||||
if ($setting) {
|
||||
return $setting;
|
||||
if (\Storage::disk('local')->has('database_created')) {
|
||||
if ($routeName === 'customer.dashboard') {
|
||||
$pageTitle = CompanySetting::getSetting('customer_portal_page_title', $company_id);
|
||||
|
||||
return $pageTitle ? $pageTitle : $defaultPageTitle;
|
||||
}
|
||||
|
||||
return 'crater';
|
||||
}
|
||||
$pageTitle = Setting::getSetting('admin_page_title');
|
||||
|
||||
return 'crater';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current login page heading
|
||||
*
|
||||
* @param $company_id
|
||||
* @return string
|
||||
*/
|
||||
function get_login_page_heading()
|
||||
{
|
||||
if (\Storage::disk('local')->has('database_created')) {
|
||||
return Setting::getSetting('login_page_heading');
|
||||
return $pageTitle ? $pageTitle : $defaultPageTitle;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current login page description
|
||||
*
|
||||
* @param $company_id
|
||||
* @return string
|
||||
*/
|
||||
function get_login_page_description()
|
||||
{
|
||||
if (\Storage::disk('local')->has('database_created')) {
|
||||
return Setting::getSetting('login_page_description');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set Active Path
|
||||
*
|
||||
@ -106,6 +71,42 @@ function set_active($path, $active = 'active')
|
||||
return call_user_func_array('Request::is', (array)$path) ? $active : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Send Mail
|
||||
*
|
||||
* @param Mailable $mailable
|
||||
* @param object $mailSender
|
||||
* @return string $to
|
||||
*/
|
||||
function send_mail(Mailable $mailable, object $mailSender = null, string $to)
|
||||
{
|
||||
if ($mailSender->bcc && $mailSender->cc) {
|
||||
\Mail::to($to)
|
||||
->bcc(explode(',', $mailSender->bcc))
|
||||
->cc(explode(',', $mailSender->cc))
|
||||
->send($mailable);
|
||||
}
|
||||
|
||||
if ($mailSender->bcc && $mailSender->cc == null) {
|
||||
\Mail::to($to)
|
||||
->bcc(explode(',', $mailSender->bcc))
|
||||
->send($mailable);
|
||||
}
|
||||
|
||||
if ($mailSender->bcc == null && $mailSender->cc) {
|
||||
\Mail::to($to)
|
||||
->cc(explode(',', $mailSender->cc))
|
||||
->send($mailable);
|
||||
}
|
||||
|
||||
if ($mailSender->bcc == null && $mailSender->cc == null) {
|
||||
\Mail::to($to)
|
||||
->send($mailable);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @return mixed
|
||||
|
||||
40
app/Traits/MailTrait.php
Normal file
40
app/Traits/MailTrait.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Crater\Traits;
|
||||
|
||||
use Crater\Mail\EstimateViewedMail;
|
||||
use Crater\Mail\InvoiceViewedMail;
|
||||
use Crater\Mail\SendEstimateMail;
|
||||
use Crater\Mail\SendInvoiceMail;
|
||||
use Crater\Mail\SendPaymentMail;
|
||||
use Crater\Models\MailSender;
|
||||
|
||||
trait MailTrait
|
||||
{
|
||||
public function setMail($model, $data)
|
||||
{
|
||||
$mailSender = MailSender::setMailConfiguration($data['mail_sender_id'], true);
|
||||
|
||||
$data['from_address'] = $mailSender->from_address;
|
||||
$data['from_name'] = $mailSender->from_name;
|
||||
|
||||
switch ($model) {
|
||||
case 'invoice':
|
||||
send_mail(new SendInvoiceMail($data), $mailSender, $data['to']);
|
||||
|
||||
break;
|
||||
|
||||
case 'estimate':
|
||||
send_mail(new SendEstimateMail($data), $mailSender, $data['to']);
|
||||
|
||||
break;
|
||||
|
||||
case 'payment':
|
||||
send_mail(new SendPaymentMail($data), $mailSender, $data['to']);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -38,15 +38,15 @@
|
||||
"barryvdh/laravel-ide-helper": "^2.6",
|
||||
"beyondcode/laravel-dump-server": "^1.0",
|
||||
"facade/ignition": "^2.3.6",
|
||||
"friendsofphp/php-cs-fixer": "^3.0",
|
||||
"fzaninotto/faker": "^1.9.1",
|
||||
"friendsofphp/php-cs-fixer": "^3.8",
|
||||
"fakerphp/faker": "^1.9.1",
|
||||
"mockery/mockery": "^1.3.1",
|
||||
"nunomaduro/collision": "^5.0",
|
||||
"pestphp/pest": "^1.0",
|
||||
"pestphp/pest-plugin-faker": "^1.0",
|
||||
"pestphp/pest-plugin-laravel": "^1.0",
|
||||
"pestphp/pest-plugin-parallel": "^0.2.1",
|
||||
"phpunit/phpunit": "^9.0"
|
||||
"phpunit/phpunit": "^9.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
@ -81,7 +81,10 @@
|
||||
"config": {
|
||||
"optimize-autoloader": true,
|
||||
"preferred-install": "dist",
|
||||
"sort-packages": true
|
||||
"sort-packages": true,
|
||||
"allow-plugins": {
|
||||
"pestphp/pest-plugin": true
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
|
||||
2347
composer.lock
generated
2347
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -7,6 +7,7 @@ use Crater\Models\ExchangeRateProvider;
|
||||
use Crater\Models\Expense;
|
||||
use Crater\Models\Invoice;
|
||||
use Crater\Models\Item;
|
||||
use Crater\Models\MailSender;
|
||||
use Crater\Models\Note;
|
||||
use Crater\Models\Payment;
|
||||
use Crater\Models\RecurringInvoice;
|
||||
@ -397,6 +398,41 @@ return [
|
||||
]
|
||||
],
|
||||
|
||||
// Mail Sender
|
||||
[
|
||||
"name" => "view mail sender",
|
||||
"ability" => "view-mail-sender",
|
||||
"model" => MailSender::class,
|
||||
'owner_only' => false,
|
||||
],
|
||||
[
|
||||
"name" => "create mail sender",
|
||||
"ability" => "create-mail-sender",
|
||||
"model" => MailSender::class,
|
||||
'owner_only' => false,
|
||||
"depends_on" => [
|
||||
'view-mail-sender',
|
||||
]
|
||||
],
|
||||
[
|
||||
"name" => "edit mail sender",
|
||||
"ability" => "edit-mail-sender",
|
||||
"model" => MailSender::class,
|
||||
'owner_only' => false,
|
||||
"depends_on" => [
|
||||
'view-mail-sender',
|
||||
]
|
||||
],
|
||||
[
|
||||
"name" => "delete mail sender",
|
||||
"ability" => "delete-mail-sender",
|
||||
"model" => MailSender::class,
|
||||
'owner_only' => false,
|
||||
"depends_on" => [
|
||||
'view-mail-sender',
|
||||
]
|
||||
],
|
||||
|
||||
// Settings
|
||||
[
|
||||
"name" => "view company dashboard",
|
||||
|
||||
@ -7,6 +7,7 @@ use Crater\Models\ExchangeRateProvider;
|
||||
use Crater\Models\Expense;
|
||||
use Crater\Models\Invoice;
|
||||
use Crater\Models\Item;
|
||||
use Crater\Models\MailSender;
|
||||
use Crater\Models\Note;
|
||||
use Crater\Models\Payment;
|
||||
use Crater\Models\RecurringInvoice;
|
||||
@ -71,6 +72,7 @@ return [
|
||||
["code" => "cs", "name" => "Czech"],
|
||||
["code" => "el", "name" => "Greek"],
|
||||
["code" => "hr", "name" => "Crotian"],
|
||||
["code" => "th", "name" => "ไทย"],
|
||||
],
|
||||
|
||||
/*
|
||||
@ -224,6 +226,17 @@ return [
|
||||
'ability' => 'view-all-notes',
|
||||
'model' => Note::class
|
||||
],
|
||||
[
|
||||
'title' => 'settings.menu_title.mail_sender',
|
||||
'group' => '',
|
||||
'name' => 'Mail Sender',
|
||||
'link' => '/admin/settings/mail-sender',
|
||||
'icon' => 'MailIcon',
|
||||
'owner_only' => false,
|
||||
'ability' => 'view-mail-sender',
|
||||
'model' => MailSender::class
|
||||
],
|
||||
|
||||
[
|
||||
'title' => 'settings.menu_title.expense_category',
|
||||
'group' => '',
|
||||
@ -234,16 +247,6 @@ return [
|
||||
'ability' => 'view-expense',
|
||||
'model' => Expense::class
|
||||
],
|
||||
[
|
||||
'title' => 'settings.mail.mail_config',
|
||||
'group' => '',
|
||||
'name' => 'Mail Configuration',
|
||||
'link' => '/admin/settings/mail-configuration',
|
||||
'icon' => 'MailIcon',
|
||||
'owner_only' => true,
|
||||
'ability' => '',
|
||||
'model' => ''
|
||||
],
|
||||
[
|
||||
'title' => 'settings.menu_title.file_disk',
|
||||
'group' => '',
|
||||
@ -274,6 +277,7 @@ return [
|
||||
'ability' => '',
|
||||
'model' => ''
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|
||||
@ -27,6 +27,7 @@ return [
|
||||
'tokenizer',
|
||||
'JSON',
|
||||
'cURL',
|
||||
'zip',
|
||||
],
|
||||
'apache' => [
|
||||
'mod_rewrite',
|
||||
|
||||
@ -37,15 +37,6 @@ class InvoiceFactory extends Factory
|
||||
});
|
||||
}
|
||||
|
||||
public function overdue()
|
||||
{
|
||||
return $this->state(function (array $attributes) {
|
||||
return [
|
||||
'status' => Invoice::STATUS_OVERDUE,
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
public function completed()
|
||||
{
|
||||
return $this->state(function (array $attributes) {
|
||||
@ -55,15 +46,6 @@ class InvoiceFactory extends Factory
|
||||
});
|
||||
}
|
||||
|
||||
public function due()
|
||||
{
|
||||
return $this->state(function (array $attributes) {
|
||||
return [
|
||||
'status' => Invoice::STATUS_DUE,
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
public function unpaid()
|
||||
{
|
||||
return $this->state(function (array $attributes) {
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
use Crater\Models\Setting;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class UpdateCraterVersion604 extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Setting::setSetting('version', '6.0.4');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class UpdateValueColumnToNullableOnSettingsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('settings', function (Blueprint $table) {
|
||||
$table->string('value')->nullable()->change();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddOverdueToInvoicesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('invoices', function (Blueprint $table) {
|
||||
$table->boolean('overdue')->default(false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('invoices', function (Blueprint $table) {
|
||||
$table->dropForeign(['overdue']);
|
||||
});
|
||||
}
|
||||
}
|
||||
27
database/migrations/2022_03_03_060121_crater_version_605.php
Normal file
27
database/migrations/2022_03_03_060121_crater_version_605.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
use Crater\Models\Setting;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CraterVersion605 extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Setting::setSetting('version', '6.0.5');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Crater\Models\Invoice;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class ChangeOverDueStatusToSent extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$overdueInvoices = Invoice::where('status', 'OVERDUE')->get();
|
||||
|
||||
if ($overdueInvoices) {
|
||||
$overdueInvoices->map(function ($overdueInvoice) {
|
||||
$overdueInvoice->status = Invoice::STATUS_SENT;
|
||||
$overdueInvoice->overdue = true;
|
||||
$overdueInvoice->save();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Crater\Models\InvoiceItem;
|
||||
use Crater\Models\Tax;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CalculateBaseValuesForInvoiceItems extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$taxes = Tax::whereRelation('invoiceItem', 'base_amount', null)->get();
|
||||
|
||||
if ($taxes) {
|
||||
$taxes->map(function ($tax) {
|
||||
$invoiceItem = InvoiceItem::find($tax->invoice_item_id);
|
||||
$exchange_rate = $invoiceItem->exchange_rate;
|
||||
$tax->exchange_rate = $exchange_rate;
|
||||
$tax->base_amount = $tax->amount * $exchange_rate;
|
||||
$tax->save();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
use Crater\Models\Setting;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class UpdateCraterVersion606 extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Setting::setSetting('version', '6.0.6');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
use Crater\Models\Company;
|
||||
use Crater\Models\MailSender;
|
||||
use Crater\Models\User;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Silber\Bouncer\BouncerFacade;
|
||||
|
||||
class CreateMailSendersTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('mail_senders', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('driver');
|
||||
$table->boolean('is_default')->default(false);
|
||||
$table->string('bcc')->nullable();
|
||||
$table->string('cc')->nullable();
|
||||
$table->string('from_address')->nullable();
|
||||
$table->string('from_name')->nullable();
|
||||
$table->json('settings')->nullable();
|
||||
$table->integer('company_id')->unsigned()->nullable();
|
||||
$table->foreign('company_id')->references('id')->on('companies');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
$users = User::where('role', 'super admin')->get();
|
||||
|
||||
foreach ($users as $user) {
|
||||
BouncerFacade::allow($user)->toManage(MailSender::class);
|
||||
}
|
||||
|
||||
$companies = Company::all();
|
||||
|
||||
$companies->map(function ($company) {
|
||||
if (env('MAIL_DRIVER') == 'smtp') {
|
||||
$settings = [
|
||||
'MAIL_HOST' => env('MAIL_HOST'),
|
||||
'MAIL_PORT' => env('MAIL_PORT'),
|
||||
'MAIL_USERNAME' => env('MAIL_USERNAME'),
|
||||
'MAIL_PASSWORD' => env('MAIL_PASSWORD'),
|
||||
'MAIL_ENCRYPTION' => env('MAIL_ENCRYPTION')
|
||||
];
|
||||
$this->createSender($settings, $company->id);
|
||||
}
|
||||
|
||||
if (env('MAIL_DRIVER') == 'mail' || env('MAIL_DRIVER') == 'sendmail') {
|
||||
$this->createSender(null, $company->id);
|
||||
}
|
||||
|
||||
if (env('MAIL_DRIVER') == 'mailgun') {
|
||||
$settings = [
|
||||
'MAILGUN_DOMAIN' => env('MAILGUN_DOMAIN'),
|
||||
'MAILGUN_SECRET' => env('MAILGUN_SECRET'),
|
||||
'MAILGUN_ENDPOINT' => env('MAILGUN_ENDPOINT'),
|
||||
];
|
||||
$this->createSender($settings, $company->id);
|
||||
}
|
||||
|
||||
if (env('MAIL_DRIVER') == 'ses') {
|
||||
$settings = [
|
||||
'MAIL_HOST' => env('MAIL_HOST'),
|
||||
'MAIL_PORT' => env('MAIL_PORT'),
|
||||
'MAIL_ENCRYPTION' => env('MAIL_ENCRYPTION'),
|
||||
'MAILGUN_DOMAIN' => env('MAILGUN_DOMAIN'),
|
||||
'SES_KEY' => env('SES_KEY'),
|
||||
'SES_SECRET' => env('SES_SECRET'),
|
||||
];
|
||||
$this->createSender($settings, $company->id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function createSender($settings, $company_id)
|
||||
{
|
||||
$data = [
|
||||
'name' => env('MAIL_DRIVER'),
|
||||
'driver' => env('MAIL_DRIVER'),
|
||||
'is_default' => true,
|
||||
'from_address' => env('MAIL_FROM_ADDRESS'),
|
||||
'from_name' => env('MAIL_FROM_NAME'),
|
||||
'settings' => $settings ?? null,
|
||||
'company_id' => $company_id
|
||||
];
|
||||
|
||||
MailSender::create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('mail_senders');
|
||||
}
|
||||
}
|
||||
@ -170,7 +170,7 @@ class CountriesTableSeeder extends Seeder
|
||||
['id' => 152,'code' => 'NR','name' => "Nauru",'phonecode' => 674],
|
||||
['id' => 153,'code' => 'NP','name' => "Nepal",'phonecode' => 977],
|
||||
['id' => 154,'code' => 'AN','name' => "Netherlands Antilles",'phonecode' => 599],
|
||||
['id' => 155,'code' => 'NL','name' => "Netherlands The",'phonecode' => 31],
|
||||
['id' => 155,'code' => 'NL','name' => "Netherlands",'phonecode' => 31],
|
||||
['id' => 156,'code' => 'NC','name' => "New Caledonia",'phonecode' => 687],
|
||||
['id' => 157,'code' => 'NZ','name' => "New Zealand",'phonecode' => 64],
|
||||
['id' => 158,'code' => 'NI','name' => "Nicaragua",'phonecode' => 505],
|
||||
|
||||
@ -275,6 +275,14 @@ class CurrenciesTableSeeder extends Seeder
|
||||
'thousand_separator' => '.',
|
||||
'decimal_separator' => ',',
|
||||
],
|
||||
[
|
||||
'name' => 'Central African Franc',
|
||||
'code' => 'XAF',
|
||||
'symbol' => 'CFA ',
|
||||
'precision' => '2',
|
||||
'thousand_separator' => ',',
|
||||
'decimal_separator' => '.',
|
||||
],
|
||||
[
|
||||
'name' => 'West African Franc',
|
||||
'code' => 'XOF',
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
FROM php:7.4-fpm-alpine
|
||||
FROM php:8.0-fpm-alpine
|
||||
|
||||
RUN apk add --no-cache \
|
||||
php7-bcmath
|
||||
php8-bcmath
|
||||
|
||||
RUN docker-php-ext-install pdo pdo_mysql bcmath
|
||||
|
||||
|
||||
@ -1 +0,0 @@
|
||||
import{G as u,aN as d,k as m,r as n,o as h,e as p,h as s,t as o,f as c,w as f,i as _,u as x}from"./vendor.d12b5734.js";const g={class:"w-full h-screen h-screen-ios"},w={class:"flex items-center justify-center w-full h-full"},y={class:"flex flex-col items-center justify-center"},b={class:"text-primary-500",style:{"font-size":"10rem"}},v={class:"mb-10 text-3xl text-primary-500"},$={setup(k){const e=u();d();const l=m(()=>{if(e.path.indexOf("customer")>-1&&e.params.company)return`/${e.params.company}/customer/dashboard`;if(e.params.catchAll){let a=e.params.catchAll.indexOf("/");return a>-1?`/${e.params.catchAll.substring(a,0)}/customer/dashboard`:"/"}else return"/admin/dashboard"});return(t,a)=>{const r=n("BaseIcon"),i=n("router-link");return h(),p("div",g,[s("div",w,[s("div",y,[s("h1",b,o(t.$t("general.four_zero_four")),1),s("h5",v,o(t.$t("general.you_got_lost")),1),c(i,{class:"flex items-center w-32 h-12 px-3 py-1 text-base font-medium leading-none text-center text-white rounded whitespace-nowrap bg-primary-500 btn-lg hover:text-white",to:x(l)},{default:f(()=>[c(r,{name:"ArrowLeftIcon",class:"mr-2 text-white icon"}),_(" "+o(t.$t("general.go_home")),1)]),_:1},8,["to"])])])])}}};export{$ as default};
|
||||
1
public/build/assets/404.e81599b7.js
Normal file
1
public/build/assets/404.e81599b7.js
Normal file
@ -0,0 +1 @@
|
||||
import{G as u,aN as d,k as m,r as n,o as h,e as p,h as s,t as o,f as c,w as f,i as _,u as x}from"./vendor.d12b5734.js";const g={class:"w-full h-screen"},w={class:"flex items-center justify-center w-full h-full"},y={class:"flex flex-col items-center justify-center"},b={class:"text-primary-500",style:{"font-size":"10rem"}},v={class:"mb-10 text-3xl text-primary-500"},$={setup(k){const e=u();d();const l=m(()=>{if(e.path.indexOf("customer")>-1&&e.params.company)return`/${e.params.company}/customer/dashboard`;if(e.params.catchAll){let a=e.params.catchAll.indexOf("/");return a>-1?`/${e.params.catchAll.substring(a,0)}/customer/dashboard`:"/"}else return"/admin/dashboard"});return(t,a)=>{const r=n("BaseIcon"),i=n("router-link");return h(),p("div",g,[s("div",w,[s("div",y,[s("h1",b,o(t.$t("general.four_zero_four")),1),s("h5",v,o(t.$t("general.you_got_lost")),1),c(i,{class:"flex items-center w-32 h-12 px-3 py-1 text-base font-medium leading-none text-center text-white rounded whitespace-nowrap bg-primary-500 btn-lg hover:text-white",to:x(l)},{default:f(()=>[c(r,{name:"ArrowLeftIcon",class:"mr-2 text-white icon"}),_(" "+o(t.$t("general.go_home")),1)]),_:1},8,["to"])])])])}}};export{$ as default};
|
||||
@ -1 +1 @@
|
||||
var L=Object.defineProperty,P=Object.defineProperties;var T=Object.getOwnPropertyDescriptors;var V=Object.getOwnPropertySymbols;var z=Object.prototype.hasOwnProperty,E=Object.prototype.propertyIsEnumerable;var U=(u,s,i)=>s in u?L(u,s,{enumerable:!0,configurable:!0,writable:!0,value:i}):u[s]=i,S=(u,s)=>{for(var i in s||(s={}))z.call(s,i)&&U(u,i,s[i]);if(V)for(var i of V(s))E.call(s,i)&&U(u,i,s[i]);return u},I=(u,s)=>P(u,T(s));import{J,B as b,k as y,L as _,M as C,Q,N as H,P as K,a0 as O,T as W,r as m,o as M,e as X,f as r,w as d,u as e,x as Y,l as Z,m as x,j as ee,i as ae,t as se,U as te,h as ne}from"./vendor.d12b5734.js";import{e as oe,d as re,b as le}from"./main.06577e8c.js";const ie=["onSubmit"],ue=ne("span",null,null,-1),ce={setup(u){const s=oe(),i=re(),F=le(),{t:v}=J();let p=b(!1),c=b(null),f=b([]);const $=b(!1);s.currentUser.avatar&&f.value.push({image:s.currentUser.avatar});const q=y(()=>({name:{required:_.withMessage(v("validation.required"),C)},email:{required:_.withMessage(v("validation.required"),C),email:_.withMessage(v("validation.email_incorrect"),Q)},password:{minLength:_.withMessage(v("validation.password_length",{count:8}),H(8))},confirm_password:{sameAsPassword:_.withMessage(v("validation.password_incorrect"),K(t.password))}})),t=O({name:s.currentUser.name,email:s.currentUser.email,language:s.currentUserSettings.language||F.selectedCompanySettings.language,password:"",confirm_password:""}),o=W(q,y(()=>t));function k(l,a){c.value=a}function N(){c.value=null,$.value=!0}async function A(){if(o.value.$touch(),o.value.$invalid)return!0;p.value=!0;let l={name:t.name,email:t.email};try{if(t.password!=null&&t.password!==void 0&&t.password!==""&&(l=I(S({},l),{password:t.password})),s.currentUserSettings.language!==t.language&&await s.updateUserSettings({settings:{language:t.language}}),(await s.updateCurrentUser(l)).data.data){if(p.value=!1,c.value||$.value){let w=new FormData;c.value&&w.append("admin_avatar",c.value),w.append("is_admin_avatar_removed",$.value),await s.uploadAvatar(w),c.value=null,$.value=!1}t.password="",t.confirm_password=""}}catch{return p.value=!1,!0}}return(l,a)=>{const w=m("BaseFileUploader"),g=m("BaseInputGroup"),B=m("BaseInput"),G=m("BaseMultiselect"),D=m("BaseInputGrid"),R=m("BaseIcon"),h=m("BaseButton"),j=m("BaseSettingCard");return M(),X("form",{class:"relative",onSubmit:te(A,["prevent"])},[r(j,{title:l.$t("settings.account_settings.account_settings"),description:l.$t("settings.account_settings.section_description")},{default:d(()=>[r(D,null,{default:d(()=>[r(g,{label:l.$tc("settings.account_settings.profile_picture")},{default:d(()=>[r(w,{modelValue:e(f),"onUpdate:modelValue":a[0]||(a[0]=n=>Y(f)?f.value=n:f=n),avatar:!0,accept:"image/*",onChange:k,onRemove:N},null,8,["modelValue"])]),_:1},8,["label"]),ue,r(g,{label:l.$tc("settings.account_settings.name"),error:e(o).name.$error&&e(o).name.$errors[0].$message,required:""},{default:d(()=>[r(B,{modelValue:e(t).name,"onUpdate:modelValue":a[1]||(a[1]=n=>e(t).name=n),invalid:e(o).name.$error,onInput:a[2]||(a[2]=n=>e(o).name.$touch())},null,8,["modelValue","invalid"])]),_:1},8,["label","error"]),r(g,{label:l.$tc("settings.account_settings.email"),error:e(o).email.$error&&e(o).email.$errors[0].$message,required:""},{default:d(()=>[r(B,{modelValue:e(t).email,"onUpdate:modelValue":a[3]||(a[3]=n=>e(t).email=n),invalid:e(o).email.$error,onInput:a[4]||(a[4]=n=>e(o).email.$touch())},null,8,["modelValue","invalid"])]),_:1},8,["label","error"]),r(g,{error:e(o).password.$error&&e(o).password.$errors[0].$message,label:l.$tc("settings.account_settings.password")},{default:d(()=>[r(B,{modelValue:e(t).password,"onUpdate:modelValue":a[5]||(a[5]=n=>e(t).password=n),type:"password",onInput:a[6]||(a[6]=n=>e(o).password.$touch())},null,8,["modelValue"])]),_:1},8,["error","label"]),r(g,{label:l.$tc("settings.account_settings.confirm_password"),error:e(o).confirm_password.$error&&e(o).confirm_password.$errors[0].$message},{default:d(()=>[r(B,{modelValue:e(t).confirm_password,"onUpdate:modelValue":a[7]||(a[7]=n=>e(t).confirm_password=n),type:"password",onInput:a[8]||(a[8]=n=>e(o).confirm_password.$touch())},null,8,["modelValue"])]),_:1},8,["label","error"]),r(g,{label:l.$tc("settings.language")},{default:d(()=>[r(G,{modelValue:e(t).language,"onUpdate:modelValue":a[9]||(a[9]=n=>e(t).language=n),options:e(i).config.languages,label:"name","value-prop":"code","track-by":"code","open-direction":"top"},null,8,["modelValue","options"])]),_:1},8,["label"])]),_:1}),r(h,{loading:e(p),disabled:e(p),class:"mt-6"},{left:d(n=>[e(p)?ee("",!0):(M(),Z(R,{key:0,name:"SaveIcon",class:x(n.class)},null,8,["class"]))]),default:d(()=>[ae(" "+se(l.$tc("settings.company_info.save")),1)]),_:1},8,["loading","disabled"])]),_:1},8,["title","description"])],40,ie)}}};export{ce as default};
|
||||
var L=Object.defineProperty,P=Object.defineProperties;var T=Object.getOwnPropertyDescriptors;var V=Object.getOwnPropertySymbols;var z=Object.prototype.hasOwnProperty,E=Object.prototype.propertyIsEnumerable;var U=(u,s,i)=>s in u?L(u,s,{enumerable:!0,configurable:!0,writable:!0,value:i}):u[s]=i,S=(u,s)=>{for(var i in s||(s={}))z.call(s,i)&&U(u,i,s[i]);if(V)for(var i of V(s))E.call(s,i)&&U(u,i,s[i]);return u},I=(u,s)=>P(u,T(s));import{J,B as b,k as y,L as _,M as C,Q,N as H,P as K,a0 as O,T as W,r as m,o as M,e as X,f as r,w as d,u as e,x as Y,l as Z,m as x,j as ee,i as ae,t as se,U as te,h as ne}from"./vendor.d12b5734.js";import{e as oe,d as re,b as le}from"./main.465728e1.js";const ie=["onSubmit"],ue=ne("span",null,null,-1),ce={setup(u){const s=oe(),i=re(),F=le(),{t:v}=J();let p=b(!1),c=b(null),f=b([]);const $=b(!1);s.currentUser.avatar&&f.value.push({image:s.currentUser.avatar});const q=y(()=>({name:{required:_.withMessage(v("validation.required"),C)},email:{required:_.withMessage(v("validation.required"),C),email:_.withMessage(v("validation.email_incorrect"),Q)},password:{minLength:_.withMessage(v("validation.password_length",{count:8}),H(8))},confirm_password:{sameAsPassword:_.withMessage(v("validation.password_incorrect"),K(t.password))}})),t=O({name:s.currentUser.name,email:s.currentUser.email,language:s.currentUserSettings.language||F.selectedCompanySettings.language,password:"",confirm_password:""}),o=W(q,y(()=>t));function k(l,a){c.value=a}function N(){c.value=null,$.value=!0}async function A(){if(o.value.$touch(),o.value.$invalid)return!0;p.value=!0;let l={name:t.name,email:t.email};try{if(t.password!=null&&t.password!==void 0&&t.password!==""&&(l=I(S({},l),{password:t.password})),s.currentUserSettings.language!==t.language&&await s.updateUserSettings({settings:{language:t.language}}),(await s.updateCurrentUser(l)).data.data){if(p.value=!1,c.value||$.value){let w=new FormData;c.value&&w.append("admin_avatar",c.value),w.append("is_admin_avatar_removed",$.value),await s.uploadAvatar(w),c.value=null,$.value=!1}t.password="",t.confirm_password=""}}catch{return p.value=!1,!0}}return(l,a)=>{const w=m("BaseFileUploader"),g=m("BaseInputGroup"),B=m("BaseInput"),G=m("BaseMultiselect"),D=m("BaseInputGrid"),R=m("BaseIcon"),h=m("BaseButton"),j=m("BaseSettingCard");return M(),X("form",{class:"relative",onSubmit:te(A,["prevent"])},[r(j,{title:l.$t("settings.account_settings.account_settings"),description:l.$t("settings.account_settings.section_description")},{default:d(()=>[r(D,null,{default:d(()=>[r(g,{label:l.$tc("settings.account_settings.profile_picture")},{default:d(()=>[r(w,{modelValue:e(f),"onUpdate:modelValue":a[0]||(a[0]=n=>Y(f)?f.value=n:f=n),avatar:!0,accept:"image/*",onChange:k,onRemove:N},null,8,["modelValue"])]),_:1},8,["label"]),ue,r(g,{label:l.$tc("settings.account_settings.name"),error:e(o).name.$error&&e(o).name.$errors[0].$message,required:""},{default:d(()=>[r(B,{modelValue:e(t).name,"onUpdate:modelValue":a[1]||(a[1]=n=>e(t).name=n),invalid:e(o).name.$error,onInput:a[2]||(a[2]=n=>e(o).name.$touch())},null,8,["modelValue","invalid"])]),_:1},8,["label","error"]),r(g,{label:l.$tc("settings.account_settings.email"),error:e(o).email.$error&&e(o).email.$errors[0].$message,required:""},{default:d(()=>[r(B,{modelValue:e(t).email,"onUpdate:modelValue":a[3]||(a[3]=n=>e(t).email=n),invalid:e(o).email.$error,onInput:a[4]||(a[4]=n=>e(o).email.$touch())},null,8,["modelValue","invalid"])]),_:1},8,["label","error"]),r(g,{error:e(o).password.$error&&e(o).password.$errors[0].$message,label:l.$tc("settings.account_settings.password")},{default:d(()=>[r(B,{modelValue:e(t).password,"onUpdate:modelValue":a[5]||(a[5]=n=>e(t).password=n),type:"password",onInput:a[6]||(a[6]=n=>e(o).password.$touch())},null,8,["modelValue"])]),_:1},8,["error","label"]),r(g,{label:l.$tc("settings.account_settings.confirm_password"),error:e(o).confirm_password.$error&&e(o).confirm_password.$errors[0].$message},{default:d(()=>[r(B,{modelValue:e(t).confirm_password,"onUpdate:modelValue":a[7]||(a[7]=n=>e(t).confirm_password=n),type:"password",onInput:a[8]||(a[8]=n=>e(o).confirm_password.$touch())},null,8,["modelValue"])]),_:1},8,["label","error"]),r(g,{label:l.$tc("settings.language")},{default:d(()=>[r(G,{modelValue:e(t).language,"onUpdate:modelValue":a[9]||(a[9]=n=>e(t).language=n),options:e(i).config.languages,label:"name","value-prop":"code","track-by":"name","open-direction":"top"},null,8,["modelValue","options"])]),_:1},8,["label"])]),_:1}),r(h,{loading:e(p),disabled:e(p),class:"mt-6"},{left:d(n=>[e(p)?ee("",!0):(M(),Z(R,{key:0,name:"SaveIcon",class:x(n.class)},null,8,["class"]))]),default:d(()=>[ae(" "+se(l.$tc("settings.company_info.save")),1)]),_:1},8,["loading","disabled"])]),_:1},8,["title","description"])],40,ie)}}};export{ce as default};
|
||||
File diff suppressed because one or more lines are too long
1
public/build/assets/BackupSetting.135768cd.js
Normal file
1
public/build/assets/BackupSetting.135768cd.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
import{_ as o}from"./main.06577e8c.js";import{o as n,e as c,g as i,k as l,r as d,l as m,w as _,j as f,h as $,t as h,s as B}from"./vendor.d12b5734.js";const k={name:"List"},v={class:"list-none"};function x(e,r,t,s,a,p){return n(),c("div",v,[i(e.$slots,"default")])}var L=o(k,[["render",x]]);const y={name:"ListItem",props:{title:{type:String,required:!1,default:""},active:{type:Boolean,required:!0},index:{type:Number,default:null}},setup(e,{slots:r}){const t="cursor-pointer pb-2 pr-0 text-sm font-medium leading-5 flex items-center";let s=l(()=>!!r.icon),a=l(()=>e.active?`${t} text-primary-500`:`${t} text-gray-500`);return{hasIconSlot:s,containerClass:a}}},g={key:0,class:"mr-3"};function C(e,r,t,s,a,p){const u=d("router-link");return n(),m(u,B(e.$attrs,{class:s.containerClass}),{default:_(()=>[s.hasIconSlot?(n(),c("span",g,[i(e.$slots,"icon")])):f("",!0),$("span",null,h(t.title),1)]),_:3},16,["class"])}var b=o(y,[["render",C]]);export{b as B,L as a};
|
||||
import{_ as o}from"./main.465728e1.js";import{o as n,e as i,g as l,k as c,r as d,l as m,w as _,j as f,h as $,t as h,s as B}from"./vendor.d12b5734.js";const k={name:"List"},v={class:"list-none"};function x(e,r,t,s,a,p){return n(),i("div",v,[l(e.$slots,"default")])}var L=o(k,[["render",x]]);const y={name:"ListItem",props:{title:{type:String,required:!1,default:""},active:{type:Boolean,required:!0},index:{type:Number,default:null}},setup(e,{slots:r}){const t="cursor-pointer pb-2 pr-0 text-sm font-medium leading-5 flex items-center";let s=c(()=>!!r.icon),a=c(()=>e.active?`${t} text-primary-500`:`${t} text-gray-500`);return{hasIconSlot:s,containerClass:a}}},g={key:0,class:"mr-3"};function C(e,r,t,s,a,p){const u=d("router-link");return n(),m(u,B(e.$attrs,{class:s.containerClass}),{default:_(()=>[s.hasIconSlot?(n(),i("span",g,[l(e.$slots,"icon")])):f("",!0),$("span",null,h(t.title),1)]),_:3},16,["class"])}var b=o(y,[["render",C]]);export{b as B,L as a};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
import{J as j,B as k,k as g,L as y,M as N,N as L,S as T,T as q,r as i,o as B,l as b,w as r,h as m,i as f,t as C,u as e,f as n,m as D,j as G,U}from"./vendor.d12b5734.js";import{u as z}from"./category.da7287ab.js";import{c as E}from"./main.06577e8c.js";const A={class:"flex justify-between w-full"},J=["onSubmit"],X={class:"p-8 sm:p-6"},F={class:"z-0 flex justify-end p-4 border-t border-gray-200 border-solid border-modal-bg"},Q={setup(H){const t=z(),u=E(),{t:p}=j();let c=k(!1);const h=g(()=>({currentCategory:{name:{required:y.withMessage(p("validation.required"),N),minLength:y.withMessage(p("validation.name_min_length",{count:3}),L(3))},description:{maxLength:y.withMessage(p("validation.description_maxlength",{count:255}),T(255))}}})),a=q(h,g(()=>t)),w=g(()=>u.active&&u.componentName==="CategoryModal");async function I(){if(a.value.currentCategory.$touch(),a.value.currentCategory.$invalid)return!0;const s=t.isEdit?t.updateCategory:t.addCategory;c.value=!0,await s(t.currentCategory),c.value=!1,u.refreshData&&u.refreshData(),d()}function d(){u.closeModal(),setTimeout(()=>{t.$reset(),a.value.$reset()},300)}return(s,o)=>{const v=i("BaseIcon"),x=i("BaseInput"),_=i("BaseInputGroup"),M=i("BaseTextarea"),V=i("BaseInputGrid"),$=i("BaseButton"),S=i("BaseModal");return B(),b(S,{show:e(w),onClose:d},{header:r(()=>[m("div",A,[f(C(e(u).title)+" ",1),n(v,{name:"XIcon",class:"w-6 h-6 text-gray-500 cursor-pointer",onClick:d})])]),default:r(()=>[m("form",{action:"",onSubmit:U(I,["prevent"])},[m("div",X,[n(V,{layout:"one-column"},{default:r(()=>[n(_,{label:s.$t("expenses.category"),error:e(a).currentCategory.name.$error&&e(a).currentCategory.name.$errors[0].$message,required:""},{default:r(()=>[n(x,{modelValue:e(t).currentCategory.name,"onUpdate:modelValue":o[0]||(o[0]=l=>e(t).currentCategory.name=l),invalid:e(a).currentCategory.name.$error,type:"text",onInput:o[1]||(o[1]=l=>e(a).currentCategory.name.$touch())},null,8,["modelValue","invalid"])]),_:1},8,["label","error"]),n(_,{label:s.$t("expenses.description"),error:e(a).currentCategory.description.$error&&e(a).currentCategory.description.$errors[0].$message},{default:r(()=>[n(M,{modelValue:e(t).currentCategory.description,"onUpdate:modelValue":o[2]||(o[2]=l=>e(t).currentCategory.description=l),rows:"4",cols:"50",onInput:o[3]||(o[3]=l=>e(a).currentCategory.description.$touch())},null,8,["modelValue"])]),_:1},8,["label","error"])]),_:1})]),m("div",F,[n($,{type:"button",variant:"primary-outline",class:"mr-3 text-sm",onClick:d},{default:r(()=>[f(C(s.$t("general.cancel")),1)]),_:1}),n($,{loading:e(c),disabled:e(c),variant:"primary",type:"submit"},{left:r(l=>[e(c)?G("",!0):(B(),b(v,{key:0,name:"SaveIcon",class:D(l.class)},null,8,["class"]))]),default:r(()=>[f(" "+C(e(t).isEdit?s.$t("general.update"):s.$t("general.save")),1)]),_:1},8,["loading","disabled"])])],40,J)]),_:1},8,["show"])}}};export{Q as _};
|
||||
import{J as j,B as k,k as g,L as y,M as N,N as L,S as T,T as q,r as i,o as B,l as b,w as r,h as m,i as f,t as C,u as e,f as n,m as D,j as G,U}from"./vendor.d12b5734.js";import{u as z}from"./category.c88b90cd.js";import{c as E}from"./main.465728e1.js";const A={class:"flex justify-between w-full"},J=["onSubmit"],X={class:"p-8 sm:p-6"},F={class:"z-0 flex justify-end p-4 border-t border-gray-200 border-solid border-modal-bg"},Q={setup(H){const t=z(),u=E(),{t:p}=j();let c=k(!1);const h=g(()=>({currentCategory:{name:{required:y.withMessage(p("validation.required"),N),minLength:y.withMessage(p("validation.name_min_length",{count:3}),L(3))},description:{maxLength:y.withMessage(p("validation.description_maxlength",{count:255}),T(255))}}})),o=q(h,g(()=>t)),w=g(()=>u.active&&u.componentName==="CategoryModal");async function I(){if(o.value.currentCategory.$touch(),o.value.currentCategory.$invalid)return!0;const s=t.isEdit?t.updateCategory:t.addCategory;c.value=!0,await s(t.currentCategory),c.value=!1,u.refreshData&&u.refreshData(),d()}function d(){u.closeModal(),setTimeout(()=>{t.$reset(),o.value.$reset()},300)}return(s,a)=>{const v=i("BaseIcon"),x=i("BaseInput"),_=i("BaseInputGroup"),M=i("BaseTextarea"),V=i("BaseInputGrid"),$=i("BaseButton"),S=i("BaseModal");return B(),b(S,{show:e(w),onClose:d},{header:r(()=>[m("div",A,[f(C(e(u).title)+" ",1),n(v,{name:"XIcon",class:"w-6 h-6 text-gray-500 cursor-pointer",onClick:d})])]),default:r(()=>[m("form",{action:"",onSubmit:U(I,["prevent"])},[m("div",X,[n(V,{layout:"one-column"},{default:r(()=>[n(_,{label:s.$t("expenses.category"),error:e(o).currentCategory.name.$error&&e(o).currentCategory.name.$errors[0].$message,required:""},{default:r(()=>[n(x,{modelValue:e(t).currentCategory.name,"onUpdate:modelValue":a[0]||(a[0]=l=>e(t).currentCategory.name=l),invalid:e(o).currentCategory.name.$error,type:"text",onInput:a[1]||(a[1]=l=>e(o).currentCategory.name.$touch())},null,8,["modelValue","invalid"])]),_:1},8,["label","error"]),n(_,{label:s.$t("expenses.description"),error:e(o).currentCategory.description.$error&&e(o).currentCategory.description.$errors[0].$message},{default:r(()=>[n(M,{modelValue:e(t).currentCategory.description,"onUpdate:modelValue":a[2]||(a[2]=l=>e(t).currentCategory.description=l),rows:"4",cols:"50",onInput:a[3]||(a[3]=l=>e(o).currentCategory.description.$touch())},null,8,["modelValue"])]),_:1},8,["label","error"])]),_:1})]),m("div",F,[n($,{type:"button",variant:"primary-outline",class:"mr-3 text-sm",onClick:d},{default:r(()=>[f(C(s.$t("general.cancel")),1)]),_:1}),n($,{loading:e(c),disabled:e(c),variant:"primary",type:"submit"},{left:r(l=>[e(c)?G("",!0):(B(),b(v,{key:0,name:"SaveIcon",class:D(l.class)},null,8,["class"]))]),default:r(()=>[f(" "+C(e(t).isEdit?s.$t("general.update"):s.$t("general.save")),1)]),_:1},8,["loading","disabled"])])],40,J)]),_:1},8,["show"])}}};export{Q as _};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
var I=Object.defineProperty,b=Object.defineProperties;var g=Object.getOwnPropertyDescriptors;var y=Object.getOwnPropertySymbols;var q=Object.prototype.hasOwnProperty,h=Object.prototype.propertyIsEnumerable;var f=(e,t,r)=>t in e?I(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,_=(e,t)=>{for(var r in t||(t={}))q.call(t,r)&&f(e,r,t[r]);if(y)for(var r of y(t))h.call(t,r)&&f(e,r,t[r]);return e},v=(e,t)=>b(e,g(t));import{J as j,L as w,O as V,T as L,k as T,aE as F,r as E,o as n,l as m,w as P,aj as O,u as c,_ as S,C as x,e as D,f as A,F as R,y as k,j as B,I as C}from"./vendor.d12b5734.js";import{o as i,m as Y}from"./main.06577e8c.js";function $(e){switch(e){case"./types/DateTimeType.vue":return i(()=>import("./DateTimeType.6886ff98.js"),["assets/DateTimeType.6886ff98.js","assets/vendor.d12b5734.js"]);case"./types/DateType.vue":return i(()=>import("./DateType.12fc8765.js"),["assets/DateType.12fc8765.js","assets/vendor.d12b5734.js"]);case"./types/DropdownType.vue":return i(()=>import("./DropdownType.2d01b840.js"),["assets/DropdownType.2d01b840.js","assets/vendor.d12b5734.js"]);case"./types/InputType.vue":return i(()=>import("./InputType.cf0dfc7c.js"),["assets/InputType.cf0dfc7c.js","assets/vendor.d12b5734.js"]);case"./types/NumberType.vue":return i(()=>import("./NumberType.7b73360f.js"),["assets/NumberType.7b73360f.js","assets/vendor.d12b5734.js"]);case"./types/PhoneType.vue":return i(()=>import("./PhoneType.29ae66c8.js"),["assets/PhoneType.29ae66c8.js","assets/vendor.d12b5734.js"]);case"./types/SwitchType.vue":return i(()=>import("./SwitchType.591a8b07.js"),["assets/SwitchType.591a8b07.js","assets/vendor.d12b5734.js"]);case"./types/TextAreaType.vue":return i(()=>import("./TextAreaType.27565abe.js"),["assets/TextAreaType.27565abe.js","assets/vendor.d12b5734.js"]);case"./types/TimeType.vue":return i(()=>import("./TimeType.8ac8afd1.js"),["assets/TimeType.8ac8afd1.js","assets/vendor.d12b5734.js"]);case"./types/UrlType.vue":return i(()=>import("./UrlType.d123ab64.js"),["assets/UrlType.d123ab64.js","assets/vendor.d12b5734.js"]);default:return new Promise(function(t,r){(typeof queueMicrotask=="function"?queueMicrotask:setTimeout)(r.bind(null,new Error("Unknown variable dynamic import: "+e)))})}}const M={props:{field:{type:Object,required:!0},customFieldScope:{type:String,required:!0},index:{type:Number,required:!0},store:{type:Object,required:!0},storeProp:{type:String,required:!0}},setup(e){const t=e,{t:r}=j(),d={value:{required:w.withMessage(r("validation.required"),V(t.field.is_required))}},a=L(d,T(()=>t.field),{$scope:t.customFieldScope}),o=T(()=>t.field.type?F(()=>$(`./types/${t.field.type}Type.vue`)):!1);return(u,s)=>{const l=E("BaseInputGroup");return n(),m(l,{label:e.field.label,required:!!e.field.is_required,error:c(a).value.$error&&c(a).value.$errors[0].$message},{default:P(()=>[(n(),m(O(c(o)),{modelValue:e.field.value,"onUpdate:modelValue":s[0]||(s[0]=p=>e.field.value=p),options:e.field.options,invalid:c(a).value.$error,placeholder:e.field.placeholder},null,8,["modelValue","options","invalid","placeholder"]))]),_:1},8,["label","required","error"])}}},N={key:0},J={props:{store:{type:Object,required:!0},storeProp:{type:String,required:!0},isEdit:{type:Boolean,default:!1},type:{type:String,default:null},gridLayout:{type:String,default:"two-column"},isLoading:{type:Boolean,default:null},customFieldScope:{type:String,required:!0}},setup(e){const t=e,r=Y();a();function d(){t.isEdit&&t.store[t.storeProp].fields.forEach(o=>{const u=t.store[t.storeProp].customFields.findIndex(s=>s.id===o.custom_field_id);if(u>-1){let s=o.default_answer;s&&o.custom_field.type==="DateTime"&&(s=C(o.default_answer,"YYYY-MM-DD HH:mm:ss").format("YYYY-MM-DD HH:mm")),t.store[t.storeProp].customFields[u]=v(_({},o),{id:o.custom_field_id,value:s,label:o.custom_field.label,options:o.custom_field.options,is_required:o.custom_field.is_required,placeholder:o.custom_field.placeholder,order:o.custom_field.order})}})}async function a(){let u=(await r.fetchCustomFields({type:t.type,limit:"all"})).data.data;u.map(s=>s.value=s.default_answer),t.store[t.storeProp].customFields=S.sortBy(u,s=>s.order),d()}return x(()=>t.store[t.storeProp].fields,o=>{d()}),(o,u)=>{const s=E("BaseInputGrid");return e.store[e.storeProp]&&e.store[e.storeProp].customFields.length>0&&!e.isLoading?(n(),D("div",N,[A(s,{layout:e.gridLayout},{default:P(()=>[(n(!0),D(R,null,k(e.store[e.storeProp].customFields,(l,p)=>(n(),m(M,{key:l.id,"custom-field-scope":e.customFieldScope,store:e.store,"store-prop":e.storeProp,index:p,field:l},null,8,["custom-field-scope","store","store-prop","index","field"]))),128))]),_:1},8,["layout"])])):B("",!0)}}};export{J as _};
|
||||
var I=Object.defineProperty,b=Object.defineProperties;var g=Object.getOwnPropertyDescriptors;var y=Object.getOwnPropertySymbols;var q=Object.prototype.hasOwnProperty,h=Object.prototype.propertyIsEnumerable;var f=(e,t,r)=>t in e?I(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,_=(e,t)=>{for(var r in t||(t={}))q.call(t,r)&&f(e,r,t[r]);if(y)for(var r of y(t))h.call(t,r)&&f(e,r,t[r]);return e},v=(e,t)=>b(e,g(t));import{J as j,L as w,O as V,T as L,k as T,aE as F,r as E,o as n,l as m,w as P,aj as O,u as c,_ as S,C as x,e as D,f as A,F as R,y as k,j as B,I as C}from"./vendor.d12b5734.js";import{o as i,m as Y}from"./main.465728e1.js";function $(e){switch(e){case"./types/DateTimeType.vue":return i(()=>import("./DateTimeType.6886ff98.js"),["assets/DateTimeType.6886ff98.js","assets/vendor.d12b5734.js"]);case"./types/DateType.vue":return i(()=>import("./DateType.12fc8765.js"),["assets/DateType.12fc8765.js","assets/vendor.d12b5734.js"]);case"./types/DropdownType.vue":return i(()=>import("./DropdownType.2d01b840.js"),["assets/DropdownType.2d01b840.js","assets/vendor.d12b5734.js"]);case"./types/InputType.vue":return i(()=>import("./InputType.cf0dfc7c.js"),["assets/InputType.cf0dfc7c.js","assets/vendor.d12b5734.js"]);case"./types/NumberType.vue":return i(()=>import("./NumberType.7b73360f.js"),["assets/NumberType.7b73360f.js","assets/vendor.d12b5734.js"]);case"./types/PhoneType.vue":return i(()=>import("./PhoneType.29ae66c8.js"),["assets/PhoneType.29ae66c8.js","assets/vendor.d12b5734.js"]);case"./types/SwitchType.vue":return i(()=>import("./SwitchType.591a8b07.js"),["assets/SwitchType.591a8b07.js","assets/vendor.d12b5734.js"]);case"./types/TextAreaType.vue":return i(()=>import("./TextAreaType.27565abe.js"),["assets/TextAreaType.27565abe.js","assets/vendor.d12b5734.js"]);case"./types/TimeType.vue":return i(()=>import("./TimeType.8ac8afd1.js"),["assets/TimeType.8ac8afd1.js","assets/vendor.d12b5734.js"]);case"./types/UrlType.vue":return i(()=>import("./UrlType.d123ab64.js"),["assets/UrlType.d123ab64.js","assets/vendor.d12b5734.js"]);default:return new Promise(function(t,r){(typeof queueMicrotask=="function"?queueMicrotask:setTimeout)(r.bind(null,new Error("Unknown variable dynamic import: "+e)))})}}const M={props:{field:{type:Object,required:!0},customFieldScope:{type:String,required:!0},index:{type:Number,required:!0},store:{type:Object,required:!0},storeProp:{type:String,required:!0}},setup(e){const t=e,{t:r}=j(),d={value:{required:w.withMessage(r("validation.required"),V(t.field.is_required))}},a=L(d,T(()=>t.field),{$scope:t.customFieldScope}),o=T(()=>t.field.type?F(()=>$(`./types/${t.field.type}Type.vue`)):!1);return(u,s)=>{const l=E("BaseInputGroup");return n(),m(l,{label:e.field.label,required:!!e.field.is_required,error:c(a).value.$error&&c(a).value.$errors[0].$message},{default:P(()=>[(n(),m(O(c(o)),{modelValue:e.field.value,"onUpdate:modelValue":s[0]||(s[0]=p=>e.field.value=p),options:e.field.options,invalid:c(a).value.$error,placeholder:e.field.placeholder},null,8,["modelValue","options","invalid","placeholder"]))]),_:1},8,["label","required","error"])}}},N={key:0},J={props:{store:{type:Object,required:!0},storeProp:{type:String,required:!0},isEdit:{type:Boolean,default:!1},type:{type:String,default:null},gridLayout:{type:String,default:"two-column"},isLoading:{type:Boolean,default:null},customFieldScope:{type:String,required:!0}},setup(e){const t=e,r=Y();a();function d(){t.isEdit&&t.store[t.storeProp].fields.forEach(o=>{const u=t.store[t.storeProp].customFields.findIndex(s=>s.id===o.custom_field_id);if(u>-1){let s=o.default_answer;s&&o.custom_field.type==="DateTime"&&(s=C(o.default_answer,"YYYY-MM-DD HH:mm:ss").format("YYYY-MM-DD HH:mm")),t.store[t.storeProp].customFields[u]=v(_({},o),{id:o.custom_field_id,value:s,label:o.custom_field.label,options:o.custom_field.options,is_required:o.custom_field.is_required,placeholder:o.custom_field.placeholder,order:o.custom_field.order})}})}async function a(){let u=(await r.fetchCustomFields({type:t.type,limit:"all"})).data.data;u.map(s=>s.value=s.default_answer),t.store[t.storeProp].customFields=S.sortBy(u,s=>s.order),d()}return x(()=>t.store[t.storeProp].fields,o=>{d()}),(o,u)=>{const s=E("BaseInputGrid");return e.store[e.storeProp]&&e.store[e.storeProp].customFields.length>0&&!e.isLoading?(n(),D("div",N,[A(s,{layout:e.gridLayout},{default:P(()=>[(n(!0),D(R,null,k(e.store[e.storeProp].customFields,(l,p)=>(n(),m(M,{key:l.id,"custom-field-scope":e.customFieldScope,store:e.store,"store-prop":e.storeProp,index:p,field:l},null,8,["custom-field-scope","store","store-prop","index","field"]))),128))]),_:1},8,["layout"])])):B("",!0)}}};export{J as _};
|
||||
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
import{l as S,u as b,j as C,e as x,g}from"./main.06577e8c.js";import{J as E,G as j,aN as T,ah as N,r as l,o as a,l as s,w as t,u as e,f as n,i as p,t as f,j as y}from"./vendor.d12b5734.js";const V={props:{row:{type:Object,default:null},table:{type:Object,default:null},loadData:{type:Function,default:()=>{}}},setup(i){const w=i,_=S();b();const v=C(),m=x(),{t:u}=E(),h=j();T(),N("utils");function B(r){v.openDialog({title:u("general.are_you_sure"),message:u("customers.confirm_delete",1),yesLabel:u("general.ok"),noLabel:u("general.cancel"),variant:"danger",hideNoButton:!1,size:"lg"}).then(c=>{c&&_.deleteCustomer({ids:[r]}).then(o=>{if(o.data.success)return w.loadData&&w.loadData(),!0})})}return(r,c)=>{const o=l("BaseIcon"),I=l("BaseButton"),d=l("BaseDropdownItem"),D=l("router-link"),k=l("BaseDropdown");return a(),s(k,{"content-loading":e(_).isFetchingViewData},{activator:t(()=>[e(h).name==="customers.view"?(a(),s(I,{key:0,variant:"primary"},{default:t(()=>[n(o,{name:"DotsHorizontalIcon",class:"h-5 text-white"})]),_:1})):(a(),s(o,{key:1,name:"DotsHorizontalIcon",class:"h-5 text-gray-500"}))]),default:t(()=>[e(m).hasAbilities(e(g).EDIT_CUSTOMER)?(a(),s(D,{key:0,to:`/admin/customers/${i.row.id}/edit`},{default:t(()=>[n(d,null,{default:t(()=>[n(o,{name:"PencilIcon",class:"w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"}),p(" "+f(r.$t("general.edit")),1)]),_:1})]),_:1},8,["to"])):y("",!0),e(h).name!=="customers.view"&&e(m).hasAbilities(e(g).VIEW_CUSTOMER)?(a(),s(D,{key:1,to:`customers/${i.row.id}/view`},{default:t(()=>[n(d,null,{default:t(()=>[n(o,{name:"EyeIcon",class:"w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"}),p(" "+f(r.$t("general.view")),1)]),_:1})]),_:1},8,["to"])):y("",!0),e(m).hasAbilities(e(g).DELETE_CUSTOMER)?(a(),s(d,{key:2,onClick:c[0]||(c[0]=$=>B(i.row.id))},{default:t(()=>[n(o,{name:"TrashIcon",class:"w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"}),p(" "+f(r.$t("general.delete")),1)]),_:1})):y("",!0)]),_:1},8,["content-loading"])}}};export{V as _};
|
||||
import{l as S,u as b,j as C,e as x,g}from"./main.465728e1.js";import{J as E,G as j,aN as T,ah as N,r as l,o as a,l as s,w as t,u as e,f as n,i as p,t as f,j as y}from"./vendor.d12b5734.js";const V={props:{row:{type:Object,default:null},table:{type:Object,default:null},loadData:{type:Function,default:()=>{}}},setup(i){const w=i,_=S();b();const v=C(),m=x(),{t:u}=E(),h=j();T(),N("utils");function B(r){v.openDialog({title:u("general.are_you_sure"),message:u("customers.confirm_delete",1),yesLabel:u("general.ok"),noLabel:u("general.cancel"),variant:"danger",hideNoButton:!1,size:"lg"}).then(c=>{c&&_.deleteCustomer({ids:[r]}).then(o=>{if(o.data.success)return w.loadData&&w.loadData(),!0})})}return(r,c)=>{const o=l("BaseIcon"),I=l("BaseButton"),d=l("BaseDropdownItem"),D=l("router-link"),k=l("BaseDropdown");return a(),s(k,{"content-loading":e(_).isFetchingViewData},{activator:t(()=>[e(h).name==="customers.view"?(a(),s(I,{key:0,variant:"primary"},{default:t(()=>[n(o,{name:"DotsHorizontalIcon",class:"h-5 text-white"})]),_:1})):(a(),s(o,{key:1,name:"DotsHorizontalIcon",class:"h-5 text-gray-500"}))]),default:t(()=>[e(m).hasAbilities(e(g).EDIT_CUSTOMER)?(a(),s(D,{key:0,to:`/admin/customers/${i.row.id}/edit`},{default:t(()=>[n(d,null,{default:t(()=>[n(o,{name:"PencilIcon",class:"w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"}),p(" "+f(r.$t("general.edit")),1)]),_:1})]),_:1},8,["to"])):y("",!0),e(h).name!=="customers.view"&&e(m).hasAbilities(e(g).VIEW_CUSTOMER)?(a(),s(D,{key:1,to:`customers/${i.row.id}/view`},{default:t(()=>[n(d,null,{default:t(()=>[n(o,{name:"EyeIcon",class:"w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"}),p(" "+f(r.$t("general.view")),1)]),_:1})]),_:1},8,["to"])):y("",!0),e(m).hasAbilities(e(g).DELETE_CUSTOMER)?(a(),s(d,{key:2,onClick:c[0]||(c[0]=$=>B(i.row.id))},{default:t(()=>[n(o,{name:"TrashIcon",class:"w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"}),p(" "+f(r.$t("general.delete")),1)]),_:1})):y("",!0)]),_:1},8,["content-loading"])}}};export{V as _};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,4 +1,4 @@
|
||||
import{aU as $r,aV as Br,aQ as Kr,aW as Hr,o as Wr,e as Xr,h as Yr}from"./vendor.d12b5734.js";import{_ as Vr}from"./main.06577e8c.js";var gr={exports:{}};/**!
|
||||
import{aU as $r,aV as Br,aQ as Kr,aW as Hr,o as Wr,e as Xr,h as Yr}from"./vendor.d12b5734.js";import{_ as Vr}from"./main.465728e1.js";var gr={exports:{}};/**!
|
||||
* Sortable 1.14.0
|
||||
* @author RubaXa <trash@rubaxa.org>
|
||||
* @author owenm <owen23355@gmail.com>
|
||||
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
import{_ as r}from"./main.06577e8c.js";import{o as s,e as o,h as C,m as l}from"./vendor.d12b5734.js";const n={},i={width:"50",height:"50",viewBox:"0 0 50 50",fill:"none",xmlns:"http://www.w3.org/2000/svg"},_=C("circle",{cx:"25",cy:"25",r:"25",fill:"#FDE4E5"},null,-1),a=C("path",{d:"M27.2031 23.6016C28.349 23.9401 29.2083 24.6562 29.7812 25.75C30.3802 26.8438 30.4714 27.9766 30.0547 29.1484C29.7422 30.0078 29.2083 30.6979 28.4531 31.2188C27.6979 31.7135 26.8516 31.974 25.9141 32V33.875C25.9141 34.0573 25.849 34.2005 25.7188 34.3047C25.6146 34.4349 25.4714 34.5 25.2891 34.5H24.0391C23.8568 34.5 23.7005 34.4349 23.5703 34.3047C23.4661 34.2005 23.4141 34.0573 23.4141 33.875V32C22.1641 32 21.0443 31.6094 20.0547 30.8281C19.8984 30.6979 19.8073 30.5417 19.7812 30.3594C19.7552 30.1771 19.8203 30.0208 19.9766 29.8906L21.3047 28.5625C21.5651 28.3281 21.8255 28.3021 22.0859 28.4844C22.4766 28.7448 22.9193 28.875 23.4141 28.875H25.9922C26.3307 28.875 26.6042 28.7708 26.8125 28.5625C27.0469 28.3281 27.1641 28.0417 27.1641 27.7031C27.1641 27.1302 26.8906 26.7656 26.3438 26.6094L22.3203 25.4375C21.4349 25.1771 20.6927 24.7083 20.0938 24.0312C19.4948 23.3542 19.1432 22.5729 19.0391 21.6875C18.9349 20.4115 19.2995 19.3177 20.1328 18.4062C20.9922 17.4688 22.0599 17 23.3359 17H23.4141V15.125C23.4141 14.9427 23.4661 14.7995 23.5703 14.6953C23.7005 14.5651 23.8568 14.5 24.0391 14.5H25.2891C25.4714 14.5 25.6146 14.5651 25.7188 14.6953C25.849 14.7995 25.9141 14.9427 25.9141 15.125V17C27.1641 17 28.2839 17.3906 29.2734 18.1719C29.4297 18.3021 29.5208 18.4583 29.5469 18.6406C29.5729 18.8229 29.5078 18.9792 29.3516 19.1094L28.0234 20.4375C27.763 20.6719 27.5026 20.6979 27.2422 20.5156C26.8516 20.2552 26.4089 20.125 25.9141 20.125H23.3359C22.9974 20.125 22.7109 20.2422 22.4766 20.4766C22.2682 20.6849 22.1641 20.9583 22.1641 21.2969C22.1641 21.5312 22.2422 21.7526 22.3984 21.9609C22.5547 22.1693 22.75 22.3125 22.9844 22.3906L27.2031 23.6016Z",fill:"#FB7178"},null,-1),h=[_,a];function H(t,e){return s(),o("svg",i,h)}var g=r(n,[["render",H]]);const V=C("circle",{cx:"25",cy:"25",r:"25",fill:"#EAF1FB"},null,-1),d=C("path",{d:"M28.25 24.5V27H20.75V24.5H28.25ZM31.7266 18.6016C31.9089 18.7839 32 19.0052 32 19.2656V19.5H27V14.5H27.2344C27.4948 14.5 27.7161 14.5911 27.8984 14.7734L31.7266 18.6016ZM25.75 19.8125C25.75 20.0729 25.8411 20.2943 26.0234 20.4766C26.2057 20.6589 26.4271 20.75 26.6875 20.75H32V33.5625C32 33.8229 31.9089 34.0443 31.7266 34.2266C31.5443 34.4089 31.3229 34.5 31.0625 34.5H17.9375C17.6771 34.5 17.4557 34.4089 17.2734 34.2266C17.0911 34.0443 17 33.8229 17 33.5625V15.4375C17 15.1771 17.0911 14.9557 17.2734 14.7734C17.4557 14.5911 17.6771 14.5 17.9375 14.5H25.75V19.8125ZM19.5 17.3125V17.9375C19.5 18.1458 19.6042 18.25 19.8125 18.25H22.9375C23.1458 18.25 23.25 18.1458 23.25 17.9375V17.3125C23.25 17.1042 23.1458 17 22.9375 17H19.8125C19.6042 17 19.5 17.1042 19.5 17.3125ZM19.5 19.8125V20.4375C19.5 20.6458 19.6042 20.75 19.8125 20.75H22.9375C23.1458 20.75 23.25 20.6458 23.25 20.4375V19.8125C23.25 19.6042 23.1458 19.5 22.9375 19.5H19.8125C19.6042 19.5 19.5 19.6042 19.5 19.8125ZM29.5 31.6875V31.0625C29.5 30.8542 29.3958 30.75 29.1875 30.75H26.0625C25.8542 30.75 25.75 30.8542 25.75 31.0625V31.6875C25.75 31.8958 25.8542 32 26.0625 32H29.1875C29.3958 32 29.5 31.8958 29.5 31.6875ZM29.5 23.875C29.5 23.6927 29.4349 23.5495 29.3047 23.4453C29.2005 23.3151 29.0573 23.25 28.875 23.25H20.125C19.9427 23.25 19.7865 23.3151 19.6562 23.4453C19.5521 23.5495 19.5 23.6927 19.5 23.875V27.625C19.5 27.8073 19.5521 27.9635 19.6562 28.0938C19.7865 28.1979 19.9427 28.25 20.125 28.25H28.875C29.0573 28.25 29.2005 28.1979 29.3047 28.0938C29.4349 27.9635 29.5 27.8073 29.5 27.625V23.875Z",fill:"currentColor"},null,-1),p=[V,d],v={props:{colorClass:{type:String,default:"text-primary-500"}},setup(t){return(e,c)=>(s(),o("svg",{width:"50",height:"50",viewBox:"0 0 50 50",fill:"none",xmlns:"http://www.w3.org/2000/svg",class:l(t.colorClass)},p,2))}},f=C("circle",{cx:"25",cy:"25",r:"25",fill:"#EAF1FB"},null,-1),u=C("path",{d:"M26.75 19.8125C26.75 20.0729 26.8411 20.2943 27.0234 20.4766C27.2057 20.6589 27.4271 20.75 27.6875 20.75H33V33.5625C33 33.8229 32.9089 34.0443 32.7266 34.2266C32.5443 34.4089 32.3229 34.5 32.0625 34.5H18.9375C18.6771 34.5 18.4557 34.4089 18.2734 34.2266C18.0911 34.0443 18 33.8229 18 33.5625V15.4375C18 15.1771 18.0911 14.9557 18.2734 14.7734C18.4557 14.5911 18.6771 14.5 18.9375 14.5H26.75V19.8125ZM33 19.2656V19.5H28V14.5H28.2344C28.4948 14.5 28.7161 14.5911 28.8984 14.7734L32.7266 18.6016C32.9089 18.7839 33 19.0052 33 19.2656Z",fill:"currentColor"},null,-1),w=[f,u],M={props:{colorClass:{type:String,default:"text-primary-500"}},setup(t){return(e,c)=>(s(),o("svg",{width:"50",height:"50",viewBox:"0 0 50 50",fill:"none",xmlns:"http://www.w3.org/2000/svg",class:l(t.colorClass)},w,2))}};export{g as D,v as _,M as a};
|
||||
import{_ as r}from"./main.465728e1.js";import{o as s,e as o,h as C,m as l}from"./vendor.d12b5734.js";const n={},i={width:"50",height:"50",viewBox:"0 0 50 50",fill:"none",xmlns:"http://www.w3.org/2000/svg"},_=C("circle",{cx:"25",cy:"25",r:"25",fill:"#FDE4E5"},null,-1),a=C("path",{d:"M27.2031 23.6016C28.349 23.9401 29.2083 24.6562 29.7812 25.75C30.3802 26.8438 30.4714 27.9766 30.0547 29.1484C29.7422 30.0078 29.2083 30.6979 28.4531 31.2188C27.6979 31.7135 26.8516 31.974 25.9141 32V33.875C25.9141 34.0573 25.849 34.2005 25.7188 34.3047C25.6146 34.4349 25.4714 34.5 25.2891 34.5H24.0391C23.8568 34.5 23.7005 34.4349 23.5703 34.3047C23.4661 34.2005 23.4141 34.0573 23.4141 33.875V32C22.1641 32 21.0443 31.6094 20.0547 30.8281C19.8984 30.6979 19.8073 30.5417 19.7812 30.3594C19.7552 30.1771 19.8203 30.0208 19.9766 29.8906L21.3047 28.5625C21.5651 28.3281 21.8255 28.3021 22.0859 28.4844C22.4766 28.7448 22.9193 28.875 23.4141 28.875H25.9922C26.3307 28.875 26.6042 28.7708 26.8125 28.5625C27.0469 28.3281 27.1641 28.0417 27.1641 27.7031C27.1641 27.1302 26.8906 26.7656 26.3438 26.6094L22.3203 25.4375C21.4349 25.1771 20.6927 24.7083 20.0938 24.0312C19.4948 23.3542 19.1432 22.5729 19.0391 21.6875C18.9349 20.4115 19.2995 19.3177 20.1328 18.4062C20.9922 17.4688 22.0599 17 23.3359 17H23.4141V15.125C23.4141 14.9427 23.4661 14.7995 23.5703 14.6953C23.7005 14.5651 23.8568 14.5 24.0391 14.5H25.2891C25.4714 14.5 25.6146 14.5651 25.7188 14.6953C25.849 14.7995 25.9141 14.9427 25.9141 15.125V17C27.1641 17 28.2839 17.3906 29.2734 18.1719C29.4297 18.3021 29.5208 18.4583 29.5469 18.6406C29.5729 18.8229 29.5078 18.9792 29.3516 19.1094L28.0234 20.4375C27.763 20.6719 27.5026 20.6979 27.2422 20.5156C26.8516 20.2552 26.4089 20.125 25.9141 20.125H23.3359C22.9974 20.125 22.7109 20.2422 22.4766 20.4766C22.2682 20.6849 22.1641 20.9583 22.1641 21.2969C22.1641 21.5312 22.2422 21.7526 22.3984 21.9609C22.5547 22.1693 22.75 22.3125 22.9844 22.3906L27.2031 23.6016Z",fill:"#FB7178"},null,-1),h=[_,a];function H(t,e){return s(),o("svg",i,h)}var g=r(n,[["render",H]]);const V=C("circle",{cx:"25",cy:"25",r:"25",fill:"#EAF1FB"},null,-1),d=C("path",{d:"M28.25 24.5V27H20.75V24.5H28.25ZM31.7266 18.6016C31.9089 18.7839 32 19.0052 32 19.2656V19.5H27V14.5H27.2344C27.4948 14.5 27.7161 14.5911 27.8984 14.7734L31.7266 18.6016ZM25.75 19.8125C25.75 20.0729 25.8411 20.2943 26.0234 20.4766C26.2057 20.6589 26.4271 20.75 26.6875 20.75H32V33.5625C32 33.8229 31.9089 34.0443 31.7266 34.2266C31.5443 34.4089 31.3229 34.5 31.0625 34.5H17.9375C17.6771 34.5 17.4557 34.4089 17.2734 34.2266C17.0911 34.0443 17 33.8229 17 33.5625V15.4375C17 15.1771 17.0911 14.9557 17.2734 14.7734C17.4557 14.5911 17.6771 14.5 17.9375 14.5H25.75V19.8125ZM19.5 17.3125V17.9375C19.5 18.1458 19.6042 18.25 19.8125 18.25H22.9375C23.1458 18.25 23.25 18.1458 23.25 17.9375V17.3125C23.25 17.1042 23.1458 17 22.9375 17H19.8125C19.6042 17 19.5 17.1042 19.5 17.3125ZM19.5 19.8125V20.4375C19.5 20.6458 19.6042 20.75 19.8125 20.75H22.9375C23.1458 20.75 23.25 20.6458 23.25 20.4375V19.8125C23.25 19.6042 23.1458 19.5 22.9375 19.5H19.8125C19.6042 19.5 19.5 19.6042 19.5 19.8125ZM29.5 31.6875V31.0625C29.5 30.8542 29.3958 30.75 29.1875 30.75H26.0625C25.8542 30.75 25.75 30.8542 25.75 31.0625V31.6875C25.75 31.8958 25.8542 32 26.0625 32H29.1875C29.3958 32 29.5 31.8958 29.5 31.6875ZM29.5 23.875C29.5 23.6927 29.4349 23.5495 29.3047 23.4453C29.2005 23.3151 29.0573 23.25 28.875 23.25H20.125C19.9427 23.25 19.7865 23.3151 19.6562 23.4453C19.5521 23.5495 19.5 23.6927 19.5 23.875V27.625C19.5 27.8073 19.5521 27.9635 19.6562 28.0938C19.7865 28.1979 19.9427 28.25 20.125 28.25H28.875C29.0573 28.25 29.2005 28.1979 29.3047 28.0938C29.4349 27.9635 29.5 27.8073 29.5 27.625V23.875Z",fill:"currentColor"},null,-1),p=[V,d],v={props:{colorClass:{type:String,default:"text-primary-500"}},setup(t){return(e,c)=>(s(),o("svg",{width:"50",height:"50",viewBox:"0 0 50 50",fill:"none",xmlns:"http://www.w3.org/2000/svg",class:l(t.colorClass)},p,2))}},f=C("circle",{cx:"25",cy:"25",r:"25",fill:"#EAF1FB"},null,-1),u=C("path",{d:"M26.75 19.8125C26.75 20.0729 26.8411 20.2943 27.0234 20.4766C27.2057 20.6589 27.4271 20.75 27.6875 20.75H33V33.5625C33 33.8229 32.9089 34.0443 32.7266 34.2266C32.5443 34.4089 32.3229 34.5 32.0625 34.5H18.9375C18.6771 34.5 18.4557 34.4089 18.2734 34.2266C18.0911 34.0443 18 33.8229 18 33.5625V15.4375C18 15.1771 18.0911 14.9557 18.2734 14.7734C18.4557 14.5911 18.6771 14.5 18.9375 14.5H26.75V19.8125ZM33 19.2656V19.5H28V14.5H28.2344C28.4948 14.5 28.7161 14.5911 28.8984 14.7734L32.7266 18.6016C32.9089 18.7839 33 19.0052 33 19.2656Z",fill:"currentColor"},null,-1),w=[f,u],M={props:{colorClass:{type:String,default:"text-primary-500"}},setup(t){return(e,c)=>(s(),o("svg",{width:"50",height:"50",viewBox:"0 0 50 50",fill:"none",xmlns:"http://www.w3.org/2000/svg",class:l(t.colorClass)},w,2))}};export{g as D,v as _,M as a};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user